Worker Process Accounts e Certificados

Quando configuramos um certificado dentro de uma aplicação IIS, é necessário concedermos direitos de leitura a chave privada do certificado em questão para as contas dos worker process do IIS. Via Alexander Strauss eu encontrei a forma de fazer isso:

  1. Através do utilitário FindPrivateKey, conseguimos identificar a chave privada, para que seja possível encontrá-la e, em seguida, conceder os direitos a mesma. Se não tiver o Microsoft SDK for .NET Framework 3.0 instalado, então voce pode baixar os exemplos de WCF da Microsoft que, dentro dele, existe um projeto chamado FindPrivateKey.sln, que é justamente o projeto que gera esse utilitário.
  2. Depois de encontrado a chave, voce pode conceder os direitos através do utilitário cacls.exe (como é mostrado no post do Alexander) ou via Windows Explorer >> Security.

Geralmente, alguns possíveis erros que podem acontecer quando voce executa um serviço WCF e o worker process não tem permissão de leitura a uma determinada chave privada. Pude detectar dois deles:

  • System.ArgumentException was unhandled Message=”The certificate ‘CN=Chave’ must have a private key that is capable of key exchange.  The process must have access rights for the private key.” Source=”System.ServiceModel”
  • CryptographicException: Keyset does not exist

É importante lembrar que se voce alterar as contas padrões no IIS para o worker process, é necessário conceder o direito de leitura a chave privada do certificado para o usuário ali determinado.

ExecutionContext

Algum dia desses eu utilizei uma classe bastante interessante fornecida pelo namespace System.Threading, chamada ExecutionContext. Ela tem a capacidade de gerenciar o contexto de execução (segurança, sincronização e transações) da thread atual, fornecendo métodos que podemos utilizar para evitar ou possibilitar a propagação do contexto para os métodos assíncronos que a nossa aplicação possa utilizar.

Quando invocamos um método assíncrono, via delegate ou via ThreadPool, o contexto é sempre propagado entre as várias threads que a aplicação está utilizando e, conseqüentemente, voce terá acesso as mesmas informações com relação a execução da thread principal e, é neste cenário, que a classe em questão entra em ação. Ela fornece quatro métodos importantes, a saber:

  • Capture: Método estático que captura o contexto de execução atual.
  • SupressFlow: Suprime a propagação do contexto entre as threads assíncronas.
  • Run: Executa um método (através de um delegate ContextCallback) em um contexto específico.
  • RestoreFlow: Restaura a propagação do contexto entre as threads assíncronas.

Para exemplificar esses quatro métodos, o código abaixo utiliza uma função chamada LogonUser que permite efetuar o logon de um determinado usuário. Se a autenticação for realizada com sucesso, personificamos a thread atual para este usuário.

using System;
using System.Threading;
using System.Globalization;
using System.Security.Principal;
using System.Runtime.InteropServices;

namespace AsyncContext
{
    class Program
    {
        [DllImport(“advapi32.dll”)]
        private static extern bool LogonUser(
            String lpszUsername,
            String lpszDomain,
            String lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            out IntPtr phToken);

        static void Main(string[] args)
        {
            IntPtr token;
            if (LogonUser(“Teste”, string.Empty, “123456”, 2, 0, out token))
            {
                WindowsIdentity.Impersonate(token);
                ThreadPool.QueueUserWorkItem(Callback, 1);
                ExecutionContext ec = ExecutionContext.Capture();
                ExecutionContext.SuppressFlow();
                    ThreadPool.QueueUserWorkItem(Callback, 2);
                    ExecutionContext.Run(ec, new ContextCallback(Callback), 3);
                    ThreadPool.QueueUserWorkItem(Callback, 4);
                ExecutionContext.RestoreFlow();
                ThreadPool.QueueUserWorkItem(Callback, 5);
                token = IntPtr.Zero;
            }
            Console.ReadLine();
        }

        static void Callback(object state)
        {
            Console.WriteLine(“Id: {0}tThread: {1}tUser: {2}”,
                state,
                Thread.CurrentThread.ManagedThreadId,
                WindowsIdentity.GetCurrent().Name);
        }
    }
}

O método chamado Callback é utilizado pelos delegates para a execução do trabalho assíncrono. Ele exibe em seu interior informações como o estado (object) que é passado como parametro para o método, id da thread corrente, o nome do usuário corrente.

O resultado da execução deste código é:

Id: 1   Thread: 3   User: ISRAELAECETeste
Id: 2   Thread: 3   User: ISRAELAECEIsrael Aece
Id: 3   Thread: 1   User: ISRAELAECETeste
Id: 4   Thread: 3   User: ISRAELAECEIsrael Aece
Id: 5   Thread: 3   User: ISRAELAECETeste

Analisando o código do método Main, se o logon for realizado com sucesso, personificamos a thread atual para o usuário chamado Teste. Em seguida delegamos para a classe ThreadPool a execução do método Callback de forma assíncrona e resultará na exibição do usuário Teste (Id: 1). A partir daqui entra em cena a classe que é tema deste post.

Através do método estático Capture da classe ExecutionContext, ela retorna um objeto do mesmo tipo, representando o contexto atual e armazena em um objeto chamado ec. Agora, através do método SupressFlow, ele evita de propagar o contexto para os métodos assíncronos e, consequentemente, as requisições realizadas através do ThreadPool, resultarão em um outro nome de usuário (Id: 2). Como vimos acima, o método Run, dado um contexto e um delegate, ele é responsável por executar o método no contexto informado e, como podemos notar no código, passamos para o método ele a instancia do contexto que capturamos mais acima e que está armazenado no objeto ec e, além dele, passamos também uma instancia do delegate ContextCallback, apontando qual será o método que deve ser executado dentro daquele contexto específico. O resultado, como poderíamos esperar, é o usuário Teste (Id: 3). Finalmente, restauramos a propagação do contexto quando invocamos o método RestoreFlow e, se analisarmos a última execução a partir da ThreadPool, temos como resultadao o usuário Teste (Id: 5) novamente.

E, como a documentação diz, enquanto o contexto está suprimido, se invocar o método Capture, ele retornará nulo. Se ainda desejar verificar se o contexto está ou não suprimido, pode analisar isso através de um método chamado IsFlowSuppressed que retorna um valor booleano indicando essa informação.

WebParts – Segurança

Assim como era de se esperar, as WebParts também fornecem um recurso bastante flexível para tratarmos da segurança das WebParts. Pode ocorrer, em algumas situações, que determinadas WebParts estarão visíveis somente aos usuários que se enquadrarem em um determinado papel, ou ainda, somente usuários específicos poderão visualizá-las.

Para podermos manipular a segurança das WebParts, temos: o evento AuthorizeWebPart da classe WebPartManager e o argumento WebPartAuthorizationEventArgs, que manda para o evento anteriormente citado informações para a customização da autorização. Além disso, ainda há uma propriedade, não menos importante, chamada AuthorizationFilter da classe WebPart, onde definimos em cada WebPart os usuários ou os papéis que terão acesso à WebPart em questão. A propriedade AuthorizationFilter e o evento AuthorizeWebPart trabalham em conjunto, ou seja, de nada adiantará se você apenas definir a propriedade AuthorizationFilter com os papéis ou os usuários que nada acontecerá. Além disso, você precisa adicionar a lógica necessária para tratar isso no evento AuthorizeWebPart.

Antes de vermos como codificar esse evento, vamos analisar as propriedades do argumento WebPartAuthorizationEventArgs que é passado para o evento AuthorizeWebPart:

Propriedade Descrição
AuthorizationFilter

Passa para o evento o valor que está definido nesta mesma propriedade da WebPart.

IsAuthorized

É através desta propriedade que informaremos se o usuário terá ou não permissão para a visualização da WebPart. Ela recebe um valor booleano, que você deverá informar através da lógica que implementar dentro do evento AuthorizeWebPart.

IsShared

Propriedade de somente leitura que especifica se a WebPart é visível/compartilhada em todos os usuários da aplicação.

Path

Propriedade de somente leitura que retorna o path do controle, caso ele seja um User Control – ASCX.

Type

Retorna o tipo do controle que está sendo autorizado.

Depois de entendermos cada uma das propriedades do argumento WebPartAuthorizationEventArgs, vamos ver como funciona isso na prática, ou seja, como devemos efetivamente validar o usuário para que ele possa ou não visualizar a WebPart. Em princípio, voltando um pouco atrás, na arquitetura das WebParts, sabemos que um server-control que está contido no interior de uma ZoneTemplate será sempre envolvido por uma GenericWebPart e, conseqüentemente, teremos a propriedade AuthorizationFilter à nossa disposição para definirmos os filtros necessários. Com isso, podemos analisar o código abaixo que ilustra esse ponto:

<html>
<body>
    <form id="form1" runat="server">
        <asp:WebPartManager ID="WebPartManager1" runat="server">
        </asp:WebPartManager>
        <table width="100%" align="center" cellspacing="0">
            <tr>
                <td width="75%" colspan="2" valign="top">
                    <asp:WebPartZone ID="WebPartZone1" runat="server">
                        <ZoneTemplate>
                            <uc1:Photos
                                ID="Photos1"
                                runat="server"
                                Title="Galeria"
                                AuthorizationFilter="Admins,Gerentes" />
                            <asp:Label
                                ID="lblNome"
                                runat="server"
                                Text="Seja bem-vindo Sr(a). Gerente."
                                AuthorizationFilter="Gerentes" />
                        </ZoneTemplate>
                    </asp:WebPartZone>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

Assim como podemos ver, ao fazer o uso do ASCX Photos definimos na propriedade AuthorizationFilter os papéis de Admins e Gerentes. Mas como já falamos anteriormente, somente isso não faz com que a autorização seja executada. É necessário que você crie essa validação através do evento AuthorizeWebPart, que veremos mais tarde. O idéia de colocar o controle Label é somente para ilustrar que há a possibilidade de acessar a propriedade AuthorizationFilter para um server-control sem ele tê-la explicitamente.

Finalmente temos que codificar o evento AuthorizeWebPart para concluirmos o processo de autorização de uma determinada WebPart. Como no exemplo definimos papéis na propriedade AuthorizationFilter, é justamente isso que devemos validar, ou seja, teremos que verificar se o usuário corrente está ou não contido dentro de um dos papéis especificados. O código abaixo demonstra essa verificação:

protected void WebPartManager1_AuthorizeWebPart(object sender,
    WebPartAuthorizationEventArgs e)
{
    if (!string.IsNullOrEmpty(e.AuthorizationFilter))
    {
        string[] roles = e.AuthorizationFilter.Split(',');
        e.IsAuthorized = Array.Exists(roles, delegate(string role)
        {
            return User.IsInRole(role);
        });
    }
    else
    {
        e.IsAuthorized = true;
    }
}

Observação: o código muda ligeramente entre VB.NET e C# porque o VB.NET não suporta métodos anônimos que são uma característica exclusiva do C#.

WebParts.zip (293.75 kb)

Validação de QueryString

Pelo que noto em grande parte dos sites que visito é que poucos se preocupam em tratar a QueryString. Nem que ao menos crie uma página de erro customizada e a defina dentro do elemento customErrors no arquivo Web.Config da aplicação. E olha que nem as grandes corporações salvam: 🙂

[ Correto ]: http://ww16.itau.com.br/atendimento/faq/resp_topicos.aspx?assunto=5
[ Erro1 (string) ]: http://ww16.itau.com.br/atendimento/faq/resp_topicos.aspx?assunto=broken
[ Erro2 (overflow) ]: http://ww16.itau.com.br/atendimento/faq/resp_topicos.aspx?assunto=9999999999999

Protegendo arquivos “não ASP.NET”

Nas versões 1.x do ASP.NET existe um problema quando nós requisitamos arquivos não ASP.NET, quais são “protegidos” através de Forms Authentication. O problema é que estes arquivos não passam pelos módulos de autenticação e autorização do ASP.NET, então independentemente das configurações no Web.Config, o recurso sempre será visível à todos os usuários, incluindo os usuários anonimos.

A solução para isso é mapear o arquivo protegido (extensão) usando o handler HttpForbiddenHandler no arquivo Web.Config da aplicação ou configurando o IIS diretamente, como eu mostrei neste post. Mas estas soluções são muito complicadas porque, no primeiro caso, o runtime do ASP.NET servirá todas as requisições e, consequentemente, a performance irá degradar; já a segunda solução, talvez é impossível porque o serviço de hospedagem não permite configurarmos o servidor deles.

O ASP.NET 2.0 resolveu este problema adicionando um novo handler chamado de DefaultHttpHandler (para os verbos: GET, HEAD e POST). Este handler será executado para todos os arquivos que não pertencem ao ASP.NET (como imagens, *.htm, *.asp, etc.), fazendo a validação do usuário e se o mesmo tem permissão para isso. Se for válido, o IIS devolverá a requisição ao responsável pelo processo deste recurso. Agora a performance é muito melhor e voce pode utilizar toda a infraestrutura (autenticação e autorização) do FormsAuthentication para proteger seus arquivos que não fazem parte do ASP.NET.

Segurança via Server.Transfer

Quando trabalhamos com acesso restrito à determinadas páginas/seções da aplicação ASP.NET, devemos ser muito cuidadoso com o uso do método Transfer da classe HttpServerUtility.

Imagine que o usuário com privilégios mínimos não tem acesso à uma determinada página por não pertencer a role “Administradores”. Coloque um botão nessa sua página que todos tem acesso e chame o método Server.Transfer apontando para a página restrita. Rode a aplicação e clique no botão. Verá que mesmo que o usuário não tenha acesso aquela página específica, o mesmo conseguirá visualizá-la.

Isso acontece porque o processo de autenticação e autorização não acontece quando se usa o método Transfer. Isso na verdade já aconteceu, ou seja, essa validação já foi feita antes do ASP.NET chamar efetivamente o recurso (página) solicitado.

Para resolver esse problema voce tem duas formas; chamar o método Redirect ao invés do Transfer. Isso forçará uma requisição do browser/cliente, qual necessitará que o processo de autenticação e autorização novamente seja executado; já a segunda possibilidade é continuar utilizando o método Transfer e, na página de destino fazer a verificação se o usuário tem ou não acesso aquele recurso. Para isso, deve-se utilizar o método IsInRole.

Security Trimming – Visualização de Items

A Microsoft implementou na versão 2.0 do ASP.NET uma opção para criar uma forma de navegação dentro de um determinado WebSite. Isso possibilita a definição dos items de menus via arquivo XML (*.sitemap), onde definimos a hierarquia dos items que serão utilizandos e, consequentemente, apresentados pelos mais diversos controles de navegação que o ASP.NET 2.0 prove.

Para aqueles que não sabem, os arquivos *.sitemap permite-nos definir (através de um atributo chamado roles do elemento siteMapNode) os papéis que o usuário deverá pertencer para que sejam possíveis a visualização ou não destes itens nos controles que os carregarem.

Há uma certa confusão quando desejamos trabalhar com “Security Trimming” dentro desta aplicação, pois não basta apenas definirmos o atributo securityTrimmingEnabled do provider para True e as roles que serão permitidas no elemento siteMapNode dentro do arquivo *.sitemap. Além disso, é necessário que, as roles definidas no arquivo *.sitemap, precisam estar em sincronia com os elementos authorization no arquivo Web.Config, pois o ASP.NET analisa as roles do usuário corrente e o elemento authorization no arquivo de configuração antes de exibir ou não o item no controle.

Mas tudo isso AINDA NÃO É SUFICIENTE. A questão é que, por default, o elemento authorization é permitido para todos os usuários (allow users=”*”), independentemente das roles, logo, se não se atentar a isso, os items continuam sendo visíveis, porém não acessíveis. Para solucionar isso, voce precisa antes de ir definindo os recursos que cada role terá, negar o acesso a todos os usuários, assim como é mostrado no trecho de código logo abaixo:

<configuration>
  <system.web>
    <authorization>
      <deny users=”*” />
    </authorization>
  </system.web>
  <location path=”Pagamentos.aspx”>
    <system.web>
      <authorization>
        <allow roles=”Gerente” />
      </authorization
    </system.web>
  </location>
  <location path=”Extrato.aspx” >
    <system.web>
      <authorization>
        <allow roles=”Funcionario” />
      </authorization>
    </system.web>
  </location>
<configuration>

Explorando Segurança do ASP.NET – WSAT

WSAT, Web Site Administration Tool, é uma aplicação ASP.NET fornecida junto com o Visual Studio .NET 2005 ou Visual Web Developer (versão Express). Esta aplicação fornece uma interface amigável para configurarmos as API’s de Membership e Roles de uma determinada aplicação ASP.NET. O WSAT se encarrega de configurar o arquivo Web.Config (se o arquivo não existir, ele mesmo o cria) automaticamente na medida em que vamos alterando e definindo alguns valores. Além disso, se você optar pelo uso do SqlMembershipProvider, é automaticamente criado um banco de dados chamado ASPNETDB.MDF dentro do diretório App_Data da aplicação corrente, já incluindo todo o schema para suportar as API’s que falamos anterioramente.

Para administrar sua aplicação ASP.NET através do WSAT, as credenciais do usuário que está executando o Visual Studio ou Visual Web Developer deve ter permissões de escrita e leitura no arquivo Web.Config e também à pasta App_Data da aplicação que está sendo administrada.

O WSAT está dividido em algumas Tabs: Application, Security e Provider. Veremos cada uma delas mais detalhadamente abaixo:

Tab Application

Nesta tab, você pode gerenciar as configurações mais comuns relacionadas à uma aplicação Web. Entre essas configurações temos:

  • Application Settings: esta opção permite-nos gerenciar as entradas de chave/valor, onde colocamos alguns valores que são utilizados pela aplicação para não deixarmos em hard-code, que comumente são: timeouts, URL para Web Services, endereços de arquivos e/ou diretórios usados dentro da aplicação. Tendo os valores aqui, faz com que se, algum dia precisarmos mudá-los, não será necessário recompilar a aplicação. Mas cuidado: os dados, por padrão, ficam em clean-text, ou seja, não será criptografado. Logo, não armazene dados sensíveis neste local.

  • Simple Mail Transfer Protocol (SMTP): se a aplicação exige o envio de e-mails você pode estar configurando o SMTP nesta seção. Para exemplificar o uso disso, lembre-se do controle PasswordRecovery que, dado um login, o ASP.NET se encarrega de enviar um e-mail para o usuário contendo a senha.

  • Application Status: você pode estar “desligando” a sua aplicação temporariamente para efetuar alguma manutenção.

  • Debug e Trace: nesta seção você pode estar definindo alguns parâmetros para configurar o Debug e Trace da sua aplicação, podendo habilitar ou desabilitar e também aplicar alguns filtros.

 

Figura 1 – Tab Application.

Tab Security

A Tab Security traz informações e faz o gerenciamento a respeito das roles da aplicação corrente para recursos específicos, o que permite restringir acesso à determinados usuários que estão contidos dentro de uma role específica. Além disso, permite também o gerencimento dos usuários da aplicação, podendo criar, alterar ou excluir usuários. É também fornecido um Security Setup Wizard, que permite-nos configurar um nível básico de segurança através deste wizard.

Temos duas formas de autenticação: Forms e Windows. Veremos sobre cada um logo abaixo:

  • Forms: este tipo de autenticação é utilizada para aplicações que são acessadas através da internet. Esta estrutura utiliza a infraestrutura de Membership e Roles para gerenciar os usuários e, através das roles, definir os recursos que ele pode ou não ter acesso.

  • Windows: este tipo já é voltado para uma rede local (intranet), onde podemos aproveitar a arquitetura do Windows para autenticar os usuários e, através dos grupos, gerenciarmos os recursos à que eles têm acesso. Neste cenário não é necessário a criação de uma página de login, pois as credenciais que serão utilizadas já foram informadas quando o usuário fez o login no Windows.

Figura 2 – Tab Security.

Como podemos ver na imagem acima, na seção Users podemos gerenciar os usuários da aplicação, inserindo, alterando ou excluindo-os. Ainda nesta seção há uma opção chamada Select authentication type, onde você define o tipo de autenticação que a sua aplicação usará. Na seção Roles você pode estar criando novas roles e ainda gerenciar os usuários que ela contém. É possível também através do link Disable Roles, habilitar ou não essa estrutura para a aplicação. Finalmente, na seção Access Rules, você pode estar definindo os acessos a determinados recursos da aplicação.

E, como podem reparar, o WSAT fará uso das classes Membership e Roles definidas para a aplicação internamente, via arquivo Web.Config.

Tab Provider

Na aba Provider você especifica o provider de Membership e Role que a sua aplicação irá utilizar. Logo, você pode ter vários providers especificados no seu arquivo Web.Config que a interface do WSAT interpreta e as exibe para que você possa selecionar.

Há duas opções nesta aba: Select a single provider for all site management data e Select a different provider for each feature (advanced). A primeira delas é usada quando utilizamos um mesmo provider para todas as funcionalidades. Já na segunda, podemos especificar diferentes providers para cada funcionalidade. As imagens abaixo mostram um exemplo destas configurações:

Figura 3 – Tab Provider.

Figura 4 – Tab Provider.

Explorando Segurança do ASP.NET – Integração com Controles

O ASP.NET 2.0 contém um conjunto completo de controles para trabalharmos com a segurança, contendo inclusive uma Tab chamada Security dentro da ToolBox do Visual Studio .NET 2005 para armazenar estes controles. Estes controles estão fortemente integrados com o Membership, e fornecem uma porção de funcionalidades que são utilizadas comumente dentro de uma aplicação Web, como por exemplo: alteração de senhas, recuperação de senhas, criação de usuários, etc. A imagem abaixo mostra os controles disponíveis dentro do Visual Studio .NET 2005, e analisaremos cada um deles mais abaixo:

Figura 1 – Controles de segurança do Visual Studio .NET 2005.

Login

O controle Login é um Composite Control, ou seja, ele é composto por vários outros controles que fazem o trabalho de validação do usuário. Entre esses controles podemos citar TextBoxes, controles de validação (RequiredFieldValidator) e um Button. Os controles RequiredFieldValidators, junto com os demais controles, são devidamente agrupados para que os mesmos não interfiram nos possíveis seções que temos na página onde ele estará hospedado. Esses validadores são necessários para evitar que o usuário submeta o formulário sem informar o Login e Senha. Fora isso, este mesmo controle ainda permite uma série de outros recursos, os quais veremos mais adiante.

Este controle usa o Membership Provider para validar o usuário na fonte de dados especificada no arquivo Web.Config. É importante dizer que este controle utiliza o provider e, se desejar que esse seu controle trabalhe com um outro provider, pode especificá-lo na propriedade MembershipProvider do mesmo. Para nos certificarmos disso podemos recorrer à ferramenta .NET Reflector e visualizar o método interno chamado AuthenticateUsingMembershipProvider da classe Login. Repare que ele recupera o provider do arquivo Web.Config e, através do método ValidateUser, valida o usuário junto a fonte de dados:

private void AuthenticateUsingMembershipProvider(AuthenticateEventArgs e) {
    MembershipProvider provider1 = LoginUtil.GetProvider(this.MembershipProvider);
    e.Authenticated = provider1.ValidateUser(this.UserNameInternal, this.PasswordInternal);
}

O controle Login ainda fornece um evento que permite-nos interceptar e customizar a autenticação do usuário dentro da aplicação. Isso é possível graças ao evento chamado Authenticate, o qual tem em sua assinatura um argumento do tipo AuthenticateEventArgs. Este argumento provê uma propriedade booleana chamada Authenticated, qual indicará ao provider se já autenticamos o usuário. Um exemplo disso é mostrado abaixo:

private void OnAuthenticate(object sender, AuthenticateEventArgs e)
{
    e.Authenticated = ValidacaoCustomizada(Login1.UserName, Login1.Password);
}

Ainda existem mais dois eventos que merecem algum comentário: LoggingIn e LoggedIn. O primeiro deles ocorre quando o usuário submete os dados para validação junto ao provider. Em outras palavras, ocorre quando o usuário pressiona o botão do controle Login. Esse evento manda em sua assinatura um argumento do tipo LoginCancelEventArgs, o qual contém uma propriedade chamada Cancel, onde você pode, em um último momento, evitar que a autenticação seja feita. Já o LoggedIn ocorre quando, as credenciais do usuário já foram validadas pelo provider e o cookie já foi criado e enfileirado para ser enviado ao browser na próxima resposta. A ordem de disparo destes eventos são: LoggingIn, Authenticate e por fim LoggedIn. Ainda temos algumas propriedades interessantes no controle Login, as quais poderemos visualizar abaixo:

Propriedade Descrição
CreateUserUrl

Especifica um link até a página que faz o cadastro de um novo usuário.

DestinationPageUrl

Especifica um link para uma página que o usuário será redirecionado caso o login seja feito com sucesso.

DisplayRememberMe

Através de um valor booleano indica se um controle do tipo CheckBox será exibido. Se o usuário marcar esse CheckBox, será criado o cookie persistente no cliente, evitando assim de fazer o login toda vez que entra na aplicação.

MembershipProvider

Indica o nome do provider que o controle Login deve utilizar.

Password

Recupera a senha do usuário.

RememberMeSet

Indica se o cookie criado será ou não persistente.

Obs.: Quando a propriedade DisplayRememberMe é definida como True, a propriedade RememberMeSet é definida com o valor do controle CheckBox que é exibido ao usuário.

UserName

Recupera o login do usuário.

LoginView

Este controle tem uma característica interessante: ele exibe um template para customizarmos um conteúdo para um determinado status ou role em que o usuário se encontra em um determinado momento. Dentro dele temos alguns templates, os quais merecem uma explicação:

  • AnonymousTemplate: especifica um template para usuários que não estão logados na aplicação, e usuários logados nunca visualizarão este template.

  • LoggedInTemplate: especifica um template padrão para usuários que estão logados na aplicação mas não contidos em qualquer role que tenha um template próprio.

  • RoleGroups: especifica um template para usuários que estão logados na aplicação, porém podemos ter aqui templates para determinadas roles e, conseqüentemente, somente usuários contidos naquela role poderão visualizar. Este controle mantém uma propriedade chamada RoleGroups do tipo RoleGroupCollection, onde podemos/devemos definir as roles através de objetos do tipo RoleGroup.

Abaixo é mostrado um exemplo de como estar utilizando o controle LoginView:

<asp:LoginView id="LoginView1" runat="server">
    <AnonymousTemplate>
        É necessário logar na aplicação.
    </AnonymousTemplate>
    <LoggedInTemplate>
        Seja bem vindo
        <asp:LoginName id="LoginName1" runat="Server" />.
    </LoggedInTemplate>
    <RoleGroups>
        <asp:RoleGroup Roles="Admin">
            <ContentTemplate>
                Sr(a). Administrador,
                <asp:LoginName id="LoginName2" runat="Server" />
            </ContentTemplate>
        </asp:RoleGroup>
    </RoleGroups>
</asp:LoginView>

PasswordRecovery

Este controle tem a finalidade de recuperar a senha de um determinado usuário. É um controle composto por TextBox, RequiredFieldValidator e um Button onde, dado um username, o provider busca na fonte de dados e o devolve. Essa devolução é realizada através de envio de e-mail para o endereço cadastrado previamente.

Para que a senha possa ser recuperada o seu provider não pode estar configurado para salvar a mesma como Hashed pois, como sabemos, é um algoritmo que não é possível reversão e, além disso, a propriedade EnablePasswordRetrieval do Membership deve estar definida como True. Se por acaso a forma de armazenamento da senha estiver como Hashed, gera então uma nova senha e envia esta para o usuário.

Agora somente nos resta configurar o e-mail para enviar ao usuário. Para isso, utilizaremos o elemento mailSettings no arquivo Web.Config. Abaixo é exibido um exemplo de como proceder nas configurações:

<system.net>
  <mailSettings>
    <smtp deliveryMethod="Network">
      <network host="mail.site.com.br" port="25" />
    </smtp>
  </mailSettings>
</system.net>

<asp:PasswordRecovery id="PasswordRecovery1" runat="server">
  <successtemplate>
    <table border="0" style="font-size:10pt;">
      <tr>
        <td>A senha foi enviada para o seu e-mail.</td>
      </tr>
    </table>
  </successtemplate>
  <mailDefinition
        From="atendimento@site.com.br
        Subject="Nova Senha"
        BodyFileName="RecuperacaoSenha.txt" />
</asp:PasswordRecovery>

Olá <% UserName %>,

A sua nova senha é <% Password %>.

Obrigado!

UserName e Password são palavras reservadas que, antes de enviar o e-mail, o ASP.NET automaticamente substitui os respectivos dados pelos valores efetivos.

LoginStatus

O controle LoginStatus fornece-nos dois estados: logado e não logado, e o mesmo consegue obter essa informação através da propriedade IsAuthenticated da classe Page. Este controle pode exibir um Link ou uma Imagem (dependendo das propriedades LoginImageUrl e LogoutImageUrl). Quando o usuário não está logado, o controle fornece um link até a página de login da aplicação. Se o usuário estiver logado, este controle fornece um link para a página de logout da aplicação. No caso do Logout internamente ele se encarrega de chamar o método SignOut da classe FormsAuthentication.

Há também um comportamento muito interessante dentro deste controle, que é a propriedade LogoutAction, a qual recebe um enumerador do tipo LogoutAction. Esta propriedade vai dizer ao controle o que ele deve fazer quando o usuário efetuar o logout na aplicação. O enumerador LogoutAction tem três opções, as quais são explicadas abaixo:

  • Redirect: redireciona o usuário para a página especificada na propriedade LogoutPageUrl e, se esta estiver vazia, o usuário é redirecionado para a página de login da aplicação, configurada no arquivo Web.Config.

  • RedirectToLoginPage: redireciona o usuário para a página de login da aplicação, configurada no arquivo Web.Config.

  • Refresh: apenas atualiza a página atual.

LoginName

O controle LoginName apenas exibe o valor contido dentro da propriedade System.Web.UI.Page.User.Identity.Name. Lembrando que, se a propriedade estiver definida com um valor vazio, o controle não é exibido. Uma restrição que há em cima deste controle é que ele não pode ser usado fora da tag form, como por exemplo no title de uma página.

CreateUserWizard

Este controle (CompositeControl) fornece uma interface para a criação de um novo usuário, utilizando a arquitetura do Membership. Como o controle confia no provider informado, ele irá obrigar o usuário a digitar informações como E-mail, Question, Answer. Se a definição da propriedade AutoGeneratePassword estiver definida como True o próprio ASP.NET se encarrega de gerar a senha aleatória e salvá-la na fonte de dados.

O controle CreateUserWizard permite-nos enviar um e-mail automaticamente ao usuário assim que o processo for concluído e, para isso, é necessário a configuração do elemento mailDefinition, bem como o SMTP no arquivo Web.Config. Há ainda algumas propriedades opcionais interessantes:

Propriedade Descrição
DisableCreatedUser

Esta propriedade indica se o usuário recém cadastrado será desabilitado na fonte de dados e, quando isso ocorre, não é permitido que o usuário acesse a aplicação, mesmo digitando as credenciais válidas.

LoginCreatedUser

Indica se o usuário que acaba de ser criado já deve estar sendo considerado como logado. Definindo-a como False, o usuário não será autenticado logo depois de criado, ou seja, ele terá que ir até o login e lá efetuá-lo se desejar acessar a aplicação.

ChangePassword

O controle ChangePassword possibilita ao usuário trocar uma senha por outra que ele desejar. Para que isso aconteça, é disponibilizado neste controle três TextBox, onde temos os seguintes campos a serem preenchidos: senha atual, nova senha e confirmação da nova senha. Este controle também permite a configuração do elemento mailDefinition para o envio da nova senha para o e-mail do usuário.