Compartir a través de


Autenticación de los Servicios de dominio de Active Directory desde ASP .NET

En este tema se muestra cómo una aplicación ASP.NET puede utilizar la autenticación de formularios para permitir a los usuarios autenticarse en Active Directory mediante el uso del Protocolo ligero de acceso a directorios (LDAP). Una vez que se autenticado y redirigido al usuario, puede utilizar el método Application_AuthenticateRequest del archivo Global.asax para almacenar un objeto GenericPrincipal en la propiedad HttpContext.User que fluye por la solicitud.

Para crear una nueva aplicación Web ASP.NET

  1. Inicie Microsoft Visual Studio .NET.

  2. En el menú Archivo, elija Nuevo y, a continuación, haga clic en Proyecto.

  3. Haga clic en Proyectos de C# en Tipos de proyecto y, a continuación, en Aplicación Web ASP.NET en Plantillas.

  4. En el cuadro Nombre, escriba FormsAuthAd.

  5. Deje el https://localhost predeterminado en el cuadro Servidor si está utilizando el servidor local. De lo contrario, agregue la ruta de acceso al servidor. Haga clic en Aceptar.

  6. Haga clic con el botón secundario en el nodo Referencias en el Explorador de soluciones y, a continuación, haga clic en Agregar referencia.

  7. En la ficha .NET del cuadro de diálogo Agregar referencia, haga clic en System.DirectoryServices.dll, en Seleccionar y, finalmente, en Aceptar.

Para agregar el código de autenticación de System.DirectoryServices

  1. En el Explorador de soluciones, haga clic con el botón secundario en el nodo del proyecto, seleccione Agregar y, a continuación, haga clic en Agregar nuevo elemento.

  2. En Plantillas, haga clic en Clase.

  3. Escriba LdapAuthentication.cs en el cuadro Nombre y, a continuación, haga clic en Abrir.

  4. Reemplace el código existente en el archivo LdapAuthentication.cs con el siguiente código:

    using System;
    using System.Text;
    using System.Collections;
    using System.Web.Security;
    
    using System.Security.Principal;    
    using System.DirectoryServices;
    
    
    namespace FormsAuth
    {
      public class LdapAuthentication
      {
        private string _path;
        private string _filterAttribute;
    
        public LdapAuthentication(string path)
        {
          _path = path;
        }
    
        public bool IsAuthenticated(string domain, string username, string pwd)
        {
          string domainAndUsername = domain + @"\" + username;
          DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
    
          try
          {
            //Bind to the native AdsObject to force authentication.
            object obj = entry.NativeObject;
    
            DirectorySearcher search = new DirectorySearcher(entry);
    
            search.Filter = "(SAMAccountName=" + username + ")";
            search.PropertiesToLoad.Add("cn");
            SearchResult result = search.FindOne();
    
            if(null == result)
            {
              return false;
            }
    
            //Update the new path to the user in the directory.
            _path = result.Path;
            _filterAttribute = (string)result.Properties["cn"][0];
          }
          catch (Exception ex)
          {
            throw new Exception("Error authenticating user. " + ex.Message);
          }
    
          return true;
        }
    
        public string GetGroups()
        {
          DirectorySearcher search = new DirectorySearcher(_path);
          search.Filter = "(cn=" + _filterAttribute + ")";
          search.PropertiesToLoad.Add("memberOf");
          StringBuilder groupNames = new StringBuilder();
    
          try
          {
            SearchResult result = search.FindOne();
            int propertyCount = result.Properties["memberOf"].Count;
            string dn;
            int equalsIndex, commaIndex;
    
            for(int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
            {
              dn = (string)result.Properties["memberOf"][propertyCounter];
           equalsIndex = dn.IndexOf("=", 1);
              commaIndex = dn.IndexOf(",", 1);
              if(-1 == equalsIndex)
              {
                return null;
              }
              groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1));
              groupNames.Append("|");
            }
          }
        catch(Exception ex)
        {
          throw new Exception("Error obtaining group names. " + ex.Message);
        }
        return groupNames.ToString();
      }
    }
    }
    

En el procedimiento anterior, el código de autenticación acepta un dominio, un nombre de usuario, una contraseña y una ruta de acceso al árbol en los Servicios de dominio de Active Directory. Este código utiliza el proveedor de directorio LDAP. El código de la página Logon.aspx llama al método LdapAuthentication.IsAuthenticated y pasa las credenciales que se obtienen del usuario. Seguidamente, se crea un objeto DirectoryEntry con la ruta de acceso al árbol de directorio, el nombre de usuario y la contraseña. El nombre de usuario debe tener el formato dominio\nombreDeUsuario.

El objeto DirectoryEntry trata de forzar el enlace de AdsObject mediante la obtención de la propiedad NativeObject. Si esta operación se realiza satisfactoriamente, el atributo CN del usuario se obtiene creando un objeto DirectorySearcher y filtrándolo en sAMAccountName. Para obtener más información acerca de sAMAccountName en el Esquema de Servicios de dominio de Active Directory, vea "sAMAccountName" o "atributo SAM-Account-Name" en la biblioteca de MSDN. Una vez autenticado el usuario, el método IsAuthenticated devuelve true. Para obtener una lista de grupos a los que pertenece el usuario, este código llama al método LdapAuthentication.GetGroups. El método LdapAuthentication.GetGroups obtiene una lista de grupos de seguridad y distribución a los que pertenece el usuario creando un objeto DirectorySearcher y filtrándolo de acuerdo con el atributo memberOf. Para obtener más información acerca de memberOf en el Esquema de Servicios de dominio de Active Directory, vea "memberOf" o "atributo Is-Member-Of-DL" en la biblioteca de MSDN. Este método devuelve una lista de grupos separados por canalizaciones (|). Recuerde que el método LdapAuthentication.GetGroups manipula y trunca las cadenas. Esto reduce la longitud de la cadena que se almacena en la cookie de autenticación. Si la cadena no se trunca, el formato de cada grupo se muestra de la siguiente manera:

CN=...,...,DC=domain,DC=com

El método LdapAuthentication.GetGroups puede devolver una cadena muy larga. Si la longitud de esta cadena es mayor que la longitud de la cookie, es posible que no se cree la cookie de autenticación. Si esta cadena puede superar posiblemente la longitud de la cookie, es recomendable almacenar la información del grupo en el objeto Cache de ASP.NET o en una base de datos. Como alternativa, también es recomendable cifrar la información del grupo y almacenarla en un campo de formulario oculto.

El código del archivo Global.asax proporciona un controlador de eventos Application_AuthenticateRequest. Este controlador de eventos recupera la cookie de autenticación de la colección Context.Request.Cookies, descifra la cookie y recupera la lista de grupos que se almacenarán en la propiedad FormsAuthenticationTicket.UserData. Los grupos aparecen en una lista separada por canalizaciones que se crea en la página Logon.aspx. El código analiza la cadena en una matriz de cadena para crear un objeto GenericPrincipal. Una vez creado el objeto GenericPrincipal, este objeto se coloca en la propiedad HttpContext.User.

Para escribir el código Global.asax

  1. En el Explorador de soluciones, haga clic con el botón secundario en Global.asax y, a continuación, haga clic en Ver código.

  2. Agregue el siguiente código a la parte superior del código subyacente del archivo Global.asax.cs:

    using System.Web.Security;
    using System.Security.Principal;
    
  3. Reemplace el controlador de eventos vacío existente de la Application_AuthenticateRequest con el siguiente código:

    void Application_AuthenticateRequest(object sender, EventArgs e)
    {
      string cookieName = FormsAuthentication.FormsCookieName;
      HttpCookie authCookie = Context.Request.Cookies[cookieName];
    
      if(null == authCookie)
      {
        //There is no authentication cookie.
        return;
      }
      FormsAuthenticationTicket authTicket = null;
      try
      {
        authTicket = FormsAuthentication.Decrypt(authCookie.Value);
      }
      catch(Exception ex)
      {
        //Write the exception to the Event Log.
        return;
      }
    if(null == authTicket)
      {
        //Cookie failed to decrypt.
        return;
      }
      //When the ticket was created, the UserData property was assigned a
      //pipe-delimited string of group names.
      string[] groups = authTicket.UserData.Split(new char[]{'|'});
      //Create an Identity.
      GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");
      //This principal flows throughout the request.
      GenericPrincipal principal = new GenericPrincipal(id, groups);
      Context.User = principal;
    }
    

En esta sección, se configuran los elementos <forms>, <authentication> y <authorization> en el archivo Web.config. Estos cambios permiten que sólo los usuarios autenticados puedan obtener acceso a la aplicación y que las solicitudes no autenticadas sean redirigidas a una página Logon.aspx. Puede modificar esta configuración para permitir que sólo determinados usuarios y grupos tengan acceso a la aplicación.

Para modificar el archivo Web.config

  1. Abra Web.config en el bloc de notas.

  2. Reemplace el código existente con el siguiente código:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.web>
        <authentication mode="Forms">
          <forms loginUrl="logon.aspx" name="adAuthCookie" timeout="10" path="/">
          </forms>
        </authentication>
        <authorization>
          <deny users="?"/>
          <allow users="*"/>
        </authorization>
        <identity impersonate="true"/>
      </system.web>
     </configuration>
    

Observe el siguiente elemento de configuración:

<identity impersonate="true"/>

Este elemento hace que ASP.NET suplante la cuenta que está configurada como anónima de los Servicios de Microsoft Internet Information Server (IIS). Como resultado de esta configuración, todas las solicitudes a esta aplicación se ejecutan bajo el contexto de seguridad de la cuenta configurada. El usuario proporciona credenciales para la autenticación en los Servicios de dominio de Active Directory, pero la cuenta que tiene acceso a los Servicios de dominio de Active Directory es la cuenta configurada.

Para configurar IIS para la autenticación anónima

  1. En el Administrador de IIS (en Herramientas administrativas) o en el complemento MMC de IIS, haga clic con el botón secundario en el sitio web para el que desea configurar la autenticación y, a continuación, haga clic en Propiedades.

  2. Haga clic en la ficha Seguridad de directorios y, a continuación, bajo Autenticación y control de acceso, haga clic en Editar.

  3. Active la casilla Autenticación anónima (denominada Habilitar el acceso anónimo en Windows Server 2003).

  4. Configure la cuenta anónima de la aplicación de manera que tenga permiso para los Servicios de dominio de Active Directory.

  5. Desactive la casilla Permitir que IIS controle las contraseñas, si existe. La cuenta IUSR*_<nombreDeEquipo>* predeterminada no tiene permiso para los Servicios de dominio de Active Directory.

Para crear la página Logon.aspx

  1. En el Explorador de soluciones, haga clic con el botón secundario en el nodo del proyecto, seleccione Agregar y, a continuación, haga clic en Agregar Web Forms.

  2. En el cuadro Nombre, escriba Logon.aspx y, a continuación, haga clic en Abrir.

  3. En el Explorador de soluciones, haga clic con el botón secundario en Logon.aspx y, a continuación, haga clic en Ver diseñador.

  4. Haga clic en la ficha HTML del Diseñador.

  5. Reemplace el código existente con el siguiente código:

    <%@ Page language="c#" AutoEventWireup="true" %>
    <%@ Import Namespace="FormsAuth" %>
    <html>
      <body>
        <form id="Login" method="post" >
          <asp:Label ID="Label1" Runat=server >Domain:</asp:Label>
          <asp:TextBox ID="txtDomain" Runat=server ></asp:TextBox><br>    
          <asp:Label ID="Label2" Runat=server >Username:</asp:Label>
          <asp:TextBox ID=txtUsername Runat=server ></asp:TextBox><br>
          <asp:Label ID="Label3" Runat=server >Password:</asp:Label>
          <asp:TextBox ID="txtPassword" Runat=server TextMode=Password></asp:TextBox><br>
          <asp:Button ID="btnLogin" Runat=server Text="Login" OnClick="Login_Click"></asp:Button><br>
          <asp:Label ID="errorLabel" Runat=server ForeColor=#ff3300></asp:Label><br>
          <asp:CheckBox ID=chkPersist Runat=server Text="Persist Cookie" />
        </form>
      </body>
    </html>
    <script runat=server>
    void Login_Click(object sender, EventArgs e)
    {
      string adPath = "LDAP://" + txtDomain.Text;
    
      LdapAuthentication adAuth = new LdapAuthentication(adPath);
      try
      {
        if(true == adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text))
        {
          string groups = adAuth.GetGroups(txtDomain.Text, txtUsername.Text, txtPassword.Text);
    
    
          //Create the ticket, and add the groups.
          bool isCookiePersistent = chkPersist.Checked;
          FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, 
                    txtUsername.Text,DateTime.Now, DateTime.Now.AddMinutes(60), isCookiePersistent, groups);
    
          //Encrypt the ticket.
          string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
    
          //Create a cookie, and then add the encrypted ticket to the cookie as data.
          HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
    
          if(true == isCookiePersistent)
          authCookie.Expires = authTicket.Expiration;
    
          //Add the cookie to the outgoing cookies collection.
          Response.Cookies.Add(authCookie);
    
          //You can redirect now.
          Response.Redirect(FormsAuthentication.GetRedirectUrl(txtUsername.Text, false));
        }
        else
        {
          errorLabel.Text = "Authentication did not succeed. Check user name and password.";
        }
      }
      catch(Exception ex)
      {
        errorLabel.Text = "Error authenticating. " + ex.Message;
      }
    }
    </script>
    
  6. Modifique la ruta de acceso en la página Logon.aspx para que apunte al servidor de directorio LDAP.

La página Logon.aspx es una página que reúne la información del usuario y los métodos de llamada de la clase LdapAuthentication. Una vez que el código autentica al usuario y obtiene una lista de grupos, crea un objeto FormsAuthenticationTicket, cifra el vale, agrega el vale cifrado a una cookie, agrega la cookie a la colección HttpResponse.Cookies y, a continuación, redirige la solicitud a la dirección URL que se solicitó originalmente.

La página WebForm1.aspx es la página que se solicitó originalmente. Cuando el usuario solicita esta página, la solicitud se redirige a la página Logon.aspx. Una vez autenticada la solicitud, ésta se redirige a la página WebForm1.aspx.

Para modificar la página WebForm1.aspx

  1. En el Explorador de soluciones, haga clic con el botón secundario en WebForm1.aspx y, a continuación, haga clic en Ver diseñador.

  2. Haga clic en la ficha HTML del Diseñador.

  3. Reemplace el código existente con el siguiente código:

    <%@ Page language="c#" AutoEventWireup="true" %>
    <%@ Import Namespace="System.Security.Principal" %>
    <html>
      <body>
        <form id="Form1" method="post" >
          <asp:Label ID="lblName" Runat=server /><br>
          <asp:Label ID="lblAuthType" Runat=server />
        </form>
      </body>
    </html>
    <script runat=server>
    void Page_Load(object sender, EventArgs e)
    {
      lblName.Text = "Hello " + Context.User.Identity.Name + ".";
      lblAuthType.Text = "You were authenticated using " + Context.User.Identity.AuthenticationType + ".";
    }
    </script>
    
  4. Guarde todos los archivos y, a continuación, compile el proyecto.

  5. Solicite la página WebForm1.aspx. Observe que es redirigido a Logon.aspx.

  6. Escriba las credenciales de inicio de sesión y, a continuación, haga clic en Enviar. Cuando es redirigido a WebForm1.aspx, observe que aparece su nombre de usuario y que LdapAuthentication es el tipo de autenticación de la propiedad Context.User.AuthenticationType.

Nota:
Se recomienda usar el cifrado del nivel de sockets seguro (SSL) cuando se utilice la autenticación por formularios. Esto se debe a que el usuario se identifica tomando como base la cookie de autenticación y el cifrado SSL de esta aplicación impide que alguien ponga en peligro la cookie de autenticación así como cualquier otra información valiosa que se esté transmitiendo.

Consulte también

Referencia

System.DirectoryServices
DirectoryEntry
DirectorySearcher

Conceptos

Temas de programación avanzada

Send comments about this topic to Microsoft.

Copyright © 2007 Microsoft Corporation. Reservados todos los derechos.