by Israel Aece
29. January 2009 14:56
Algumas funcionalidades de segurança do WCF exigem que se utilize certificados para proteger a mensagem. Eu tenho escrito sobre algumas dessas funcionalidades aqui e, no download do código fonte, o certificado não está junto com o projeto. Com isso, ao rodar a aplicação, voce receberá uma exceção dizendo que não foi possível localizar este certificado. Isso aconteceu recentemente com o artigo sobre customização de autenticação e autorização e que o leitor Marco Tulio apontou aqui.
Neste artigo específico, para que voce consiga rodá-lo, o primeiro passo é criar um certificado de testes a partir do utilitário makecert.exe que, por sua vez, vem juntamente com o SDK do .NET Framework. Para utilizá-lo, basta definir algumas configurações necessárias para a geração do certificado, algo como é mostrado abaixo:
C:\>makecert -sr LocalMachine -ss TrustedPeople -sky exchange -pe -a sha1 -n "CN=localhost" C:\localhost.cer
Observação: Para entender cada uma dessas opções que o utilitário fornece, consulte este artigo.
Depois do certificado criado, então nos resta configurá-lo para que o serviço possa fazer uso dele. Ao abrir o arquivo de configuração do host, efetue a mudança do certificado, apontando para este que foi recém criado. O código ficará semelhante ao qual é mostrado abaixo:
<serviceCredentials>
<serviceCertificate
findValue="localhost"
storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectName" />
<!-- Outras Configurações -->
</serviceCredentials>
Depois disso, execute o host separadamente e atualize a referencia no projeto cliente para que a chave pública seja alterada.
Para finalizar, ainda falando do artigo que explora a customização da autenticação e autorização no WCF, é necessário alterar o path dos arquivos XML que estão dentro da classe/arquivo XmlSecurityHelper.
by Israel Aece
28. January 2009 14:57
Algum tempo atrás eu falei comentei aqui sobre vários performance counters que foram adicionados ao runtime do WCF, disponibilizando diversas informações a respeito da execução dos serviços, tais como: número de chamadas, transações, segurança, etc.
Como sabemos, podemos fazer uso do IIS como host de serviços WCF e, com isso, utilizar alguns performance counters exclusivos de aplicações Web, instalados juntamente com o ASP.NET. Esses performance counters mensuram, entre várias informações importantes, a quantidade de requisições para uma determinada aplicação ou para um worker process. Utilizar esses performance counters para mensurar requisições para serviços WCF não pode ser muito confiável.
Há funcionalidades que quando habilitadas nos serviços WCF, como é o caso das reliable messages, fazem com que várias outras requisições sejam efetuadas nos bastidores, garantindo com que este recurso funcione e, como já era de se esperar, representará mais do que uma "requisição ASP.NET", não refletindo exatamente o que está ocorrendo naquele momento. Quando precisar mensurar alguma estatística de serviços WCF, independentemente de onde eles estejam sendo hospedados (Windows Service, IIS, etc.), sempre opte por utilizar os performance counters exclusivos, agrupando as informações através de contadores específicos para cada funcionalidade, como é caso dos contadores que contabilizam as reliable messages.
by Israel Aece
26. January 2009 14:59
Uma das funcionalidades mais interessantes do .NET Framework ao meu ver é o CAS - Code Access Security. Toda aplicação que roda sobre a plataforma .NET pode interagir de forma direta ou indireta com o CAS e, com isso demandar os privilégios necessários para que ela possa ser executada.
Quando a aplicação é inicializada, a mesma é carregada para dentro de um processo, que é chamado também de host. Esse host extrai e examina a evidência do Assembly, podendo diferentes informações serem coletadas de acordo com a origem do mesmo. A evidência consiste no strong-name, zona e publicador do Assembly. Depois de capturada, essa evidência é passada para o sistema de segurança do .NET Framework (CAS) para que o mesmo avalie e conceda as devidas permissões para o Assembly.
A partir deste momento, baseando-se na evidência extraída do Assembly, o runtime security policy começará a avaliar a “árvore” de code groups. Se a condição for atendida, dizemos que o Assembly é membro do code group e, além disso, o conjunto de permissões (permission set) vinculadas a essa condição será concedido ao Assembly. Caso contrário, possíveis code groups que estiverem abaixo da condição não atendida, não serão avaliados e, obviamente, não serão concedidos. Depois deste processo, a união dos conjuntos de permissões é computada e esse processo é repetido para cada nível das políticas de segurança (policy levels) que são: User, Machine e Enterprise. Finalmente, depois de todos os níveis avaliados, o Assembly receberá a interseção de todos os grupos de permissões entre os níveis, e o Assembly receberá o que chamamos de Final Permission Grant (FG).
Essas permissões são definidas a partir do utilitário caspol.exe para aplicações Windows ou, para aplicações ASP.NET, através dos arquivos *.config que estão localizados no diretório do .NET Framework. Independentemente do tipo de aplicação, mesmo que ela ganhe permissão para acesso ao sistema de arquivos, isso não quer dizer que a aplicação irá executar uma operação (de escrita ou leitura) com sucesso.
A questão é que o CAS garante as permissões que o código tem sobre o sistema operacional. Quando executamos uma aplicação ela está sempre associada à uma identidade dentro do sistema operacional. Em aplicações Windows o padrão é rodar com as credenciais do usuário corrente que está logado no sistema operacional; já em aplicações ASP.NET, o que prevalece é o usuário do IIS, mais precisamente, a identidade definida na criação do worker process. Com esse comportamento, de nada adianta a aplicação receber o FileIOPermission se o usuário que está associado à execução naquele momento não possuir os devidos privilégios de acesso dentro do Windows.
by Israel Aece
23. January 2009 15:07
Há algum tempo escrevi um artigo sobre transferencia e codificação de dados no WCF. Quando optamos por utilizar o modelo streaming, há um cuidado extra que devemos tomar para efetuar o fechamento dele. Neste cenário sempre há o desafio de saber quando e quem fecha o stream e que foram abordadas no artigo mecionado acima.
Quando alguém envia um stream para o outro lado, este deverá permanecer aberto até que a transferencia seja concluída. Não temos problemas quando o stream é passado diretamente com parametro ou como retorno de uma operação. O problema começa a acontecer quando voce altera a mensagem para que, além do stream, informe dados adicionais, como é mostrado no artigo e ressalto aqui:
[MessageContract]
public class StreamData
{
[MessageHeader]
public string NomeDoArquivo;
[MessageHeader]
public int Tamanho;
[MessageBodyMember]
public Stream Conteudo;
}
Ao retornar esse objeto, o stream relacionado a ele ficará aberto, causando problemas futuros. O WCF possui uma propriedade chamada AutoDisposeParameters, que está acessível através do atributo OperationBehaviorAttribute. Essa propriedade que, por padrão é True, diz ao runtime do WCF para invocar o método Dispose de todos os parametros (input e output) e dos objetos de retorno que implementam a Interface IDisposable e, a partir de agora, conseguimos entender porque quando lidamos com a classe Stream diretamente (ou uma de suas derivadas), o stream é devidamente fechado.
Como já deve suspeitar, o que nos resta fazer é também implementar a Interface IDisposable na classe StreamData e, dentro do método Dispose, invocar o método Dispose dos membros internos, garantindo assim, que o arquivo que está sendo utilizado por essa classe, seja fechado quando o método retornar.
[MessageContract]
public class StreamData : IDisposable
{
[MessageHeader]
public string NomeDoArquivo;
[MessageHeader]
public int Tamanho;
[MessageBodyMember]
public Stream Conteudo;
public void Dispose()
{
if (this.Conteudo != null)
this.Conteudo.Dispose();
}
}
by Israel Aece
22. January 2009 15:12
Ao fazer a referencia para um ASP.NET Web Services (ASMX), automaticamente o proxy é gerado. Antes do WCF, ao referenciar serviços ASMX a versão assíncrona (BeginXXX/EndXXX) dos métodos expostos por ele também eram criados.
Utilizando o Visual Studio .NET 2008, esse comportamento mudou um pouco. Agora temos uma opção chamada "Add Service Reference..." que, dado um endereço (seja ele para um serviço ASP.NET Web Services ou WCF), irá gerar o proxy. A questão é que este proxy baseia-se na infraestrutura do WCF (ClientBase<TChannel>), e a geração dos respectivos métodos assíncronos somente acontecerá se a opção "Generate asynchronous operations" do botão "Advanced" estiver selecionada (maiores detalhes neste artigo). Do contrário, a única forma assíncrona de trabalhar é utilizando o modelo de eventos.
Se quiser continuar gerando o proxy da forma antiga, ou seja, aquele que herda da classe SoapHttpClientProtocol, será necessário recorrer ao utilitário wsdl.exe, como é mostrado abaixo:
C:\>wsdl http://localhost:54509/WebService1/Service.asmx /out:C:\Temp\Proxy.cs
ebe8f4fa-faa1-4d9a-815d-99bc032bcae6|1|3.0
Tags:
ASP.NET | Async
by Israel Aece
22. January 2009 15:11
As seções connectionStrings e appSettings são as únicas que podemos acessar diretamente no código sem nenhum tipo de problema, mesmo quando a aplicação está sendo executada em um ambiente parcialmente confiável. Por parcialmente confiável em uma uma aplicação ASP.NET, entenda como o trust level esteja definido como "Medium" ou algo abaixo disso:
<trust level="Medium"/>
Neste caso, qualquer outra seção (authentication, smtp, globalization, etc.) que tentarmos acessar em um neste ambiente, uma exceção do tipo SecurityException será lançada informando que não possuímos a permissão necessária que, neste caso, é ConfigurationPermission. Note que só o fato de acessar a seção já provoca o disparo da exceção:
AuthenticationSection section =
(AuthenticationSection)WebConfigurationManager.GetSection("system.web/authentication");
Response.Write(section.Mode.ToString());
Quem determina essa restrição é o atributo requirePermission que é configurado no registro da seção dentro do arquivo de configuração. Por padrão, ele é definido como True e, como dito acima, somente as seções connectionStrings e appSettings são definidas como False, como se pode notar no arquivo machine.config. Somente altere a configuração padrão caso voce realmente saiba o que está fazendo e, principalmente, conhecendo as implicações que isso pode causar. Além disso, é importante dizer que voce também pode determinar essa restrição quando voce cria uma seção de configuração customizada.
by Israel Aece
22. January 2009 15:09
Ao efetuar o deploy de uma aplicação que utiliza a configuração padrão de um projeto do tipo WCF Service (arquivos *.svc), obrigatoriamente voce precisa permitir o acesso anônimo ao diretório virtual. Caso essa configuração não seja realizada, ao tentar acessar o serviço uma exceção do tipo NotSupportedException será disparada:
Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.
Habilitar a autenticação anônima resolve o problema, mas em alguns cenários isso não é aceitável. A forma de resolver isso é alinhar as configurações de autenticação do serviço (arquivo Web.config) com as configurações do diretório virtual. O primeiro passo é desabilitar o acesso anônimo no diretório virtual, permitindo apenas a autenticação Windows. Neste caso, a configuração do binding deve ser definida como autenticação Windows, refletindo a mesma configuração do IIS; já quando o modo de seguraça estiver definida como TransportCredentialOnly que "desliga" o acesso anônimo ao serviço. Com a configuração abaixo já é possível acessar o serviço sem o acesso anônimo habilitado no IIS:
<bindings>
<basicHttpBinding>
<binding name="bndConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
Um outro detalhe importante, é que endpoints para publicação do documento WSDL também exigem a autenticação anônima, e se tiver este endpoint no serviço, a mesma exceção que vimos acima será disparada. Para contornar este problema, voce deverá utilizar as mesmas regras de configurações de autenticação para este endpoint mas, os bindings exclusivos para publicação de metadados (mex*) não possuem características de segurança que possam ser configuradas. Podemos configurar o endpoint que expõe os metadados a partir de bindings convencionais e, com isso, ter acesso à todas as configurações de segurança que o WCF fornece. Abaixo consta a configuração geral deste cenário:
<endpoint
address=""
binding="basicHttpBinding"
contract="IService"
bindingConfiguration="bndConfig" />
<endpoint
address="mex"
binding="basicHttpBinding"
contract="IMetadataExchange"
bindingConfiguration="bndConfig" />
<bindings>
<basicHttpBinding>
<binding name="bndConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
by Israel Aece
22. January 2009 15:08
Está disponível a partir deste link uma atualização para o .NET Framework 3.5 SP1. Esta atualização também faz algumas poucas mudanças no WCF e, entre elas, o envio correto do código de status do protocolo HTTP quando a autenticação via HTTP é inválida.
Como já foi mencionado neste kb, quando utilizamos um autenticador customizado no WCF, disparamos a exceção SecurityTokenValidationException para informar ao runtime que o usuário é inválido. Quando o runtime identifica essa exceção, ele traduz a mesma para o código 403 (Forbidden) do HTTP. A mudança que é realizada com esta atualização é que ao invés de retornar 403, passará a retornar o código 401 (Unauthorized), que acaba sendo mais coerente com a situação.