ASP.NET からの Active Directory ドメイン サービス認証

このトピックは、Lightweight Directory Access Protocol (LDAP) を使用してユーザーが Active Directory ドメイン サービスに対して認証を受けられるように、ASP.NET アプリケーションでフォーム認証を使用する方法の手順を示したものです。ユーザーが認証され、リダイレクトされると、Global.asax ファイルの Application_AuthenticateRequest メソッドを使用して、要求全体にわたって使用される HttpContext.User プロパティに GenericPrincipal オブジェクトを格納することができます。

新しい ASP.NET Web アプリケーションを作成するには

  1. Microsoft Visual Studio .NET を起動します。

  2. [ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。

  3. [プロジェクトの種類] の [Visual C# プロジェクト] をクリックして、[テンプレート][ASP.NET Web アプリケーション] をクリックします。

  4. [名前] ボックスに、「FormsAuthAd」と入力します。

  5. ローカル サーバーを使用している場合は、[サーバー] ボックスの既定の https://localhost をそのままにしておきます。それ以外の場合は、サーバーへのパスを追加します。[OK] をクリックします。

  6. [ソリューション エクスプローラ][参照] ノードを右クリックして、[参照の追加] をクリックします。

  7. [参照の追加] ダイアログ ボックスの [.NET] タブで、System.DirectoryServices.dll をクリックして、[選択] をクリックし、[OK] をクリックします。

System.DirectoryServices 認証コードを追加するには

  1. [ソリューション エクスプローラ] で、プロジェクト ノードを右クリックして、[追加] をポイントし、[新しいアイテムの追加] をクリックします。

  2. [テンプレート][クラス] をクリックします。

  3. [名前] ボックスに「LdapAuthentication.cs」と入力して、[開く] をクリックします。

  4. LdapAuthentication.cs ファイル内の既存のコードを、次のコードで置き換えます。

    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();
      }
    }
    }
    

前の手順で、認証コードにより、ドメイン、ユーザー名、パスワード、および Active Directory ドメイン サービス内のツリーへのパスが受け入れられます。このコードでは、LDAP ディレクトリ プロバイダを使用します。Logon.aspx ページ内のコードは、LdapAuthentication.IsAuthenticated メソッドを呼び出し、ユーザーから収集した資格情報を渡します。次に、ディレクトリ ツリーへのパス、ユーザー名、およびパスワードを使用して、DirectoryEntry オブジェクトを作成します。ユーザー名は、"ドメイン\ユーザー名" の形式にする必要があります。

次に、DirectoryEntry オブジェクトが、NativeObject プロパティを取得して、AdsObject のバインドを強制的に試行します。これが成功すると、DirectorySearcher オブジェクトを作成して、sAMAccountName でのフィルタ処理を行うことにより、ユーザーの CN 属性を取得します。Active Directory ドメイン サービス スキーマ内の 詳細については、 sAMAccountName については、MSDN ライブラリの「sAMAccountName」または「SAM-Account-Name 属性」を参照してください。ユーザーが認証されると、IsAuthenticated は true を返します。ユーザーが属しているグループの一覧を取得するために、このコードは、LdapAuthentication.GetGroups メソッドを呼び出します。LdapAuthentication.GetGroups メソッドは、DirectorySearcher オブジェクトを作成して、memberOf 属性に従ってフィルタ処理することにより、セキュリティの一覧と、ユーザーが属している配布グループを取得します。Active Directory ドメイン サービス スキーマの 詳細については、 memberOf については、MSDN ライブラリの「memberOf」または「Is-Member-Of-DL 属性」を参照してください。このメソッドは、パイプ (|) で区切られたグループの一覧を返します。LdapAuthentication.GetGroups メソッドは、文字列を操作して、切り詰めを行うことに注意してください。これにより、認証 Cookie に格納されている文字列の長さが縮小されます。文字列を切り詰めない場合、各グループの形式は、次のようになります。

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

LdapAuthentication.GetGroups メソッドは、非常に長い文字列を返す可能性があります。この文字列の長さが Cookie の長さより大きい場合、認証 Cookie が作成されない場合があります。この文字列が Cookie の長さを超える可能性がある場合、ASP.NET キャッシュ オブジェクトまたはデータベースにグループ情報を格納することができます。または、グループ情報を暗号化して、隠しフォーム フィールドにこの情報を格納することもできます。

Global.asax ファイル内のコードは、Application_AuthenticateRequest イベント ハンドラを提供します。このイベント ハンドラは、Context.Request.Cookies コレクションから認証 Cookie を取得して、Cookie の暗号化を解除し、FormsAuthenticationTicket.UserData プロパティに格納されるグループの一覧を取得します。各グループは、Logon.aspx ページに作成される、パイプで区切られた一覧になっています。コードでは、文字列配列内の文字列を解析して、GenericPrincipal オブジェクトを作成します。GenericPrincipal オブジェクトが作成されると、このオブジェクトは HttpContext.User プロパティに配置されます。

Global.asax コードを記述するには

  1. [ソリューション エクスプローラ] で、[Global.asax] を右クリックして、[コードの表示] をクリックします。

  2. 次のコードを、Global.asax.cs ファイルのコード ビハインドの最上部に追加します。

    using System.Web.Security;
    using System.Security.Principal;
    
  3. Application_AuthenticateRequest の既存の空のイベント ハンドラを、次のコードで置き換えます。

    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;
    }
    

このセクションでは、Web.config ファイルの <forms>、<authentication>、および <authorization> の各要素の構成を行います。これらの変更により、認証されたユーザーだけがアプリケーションにアクセス可能となり、認証されていない要求は Logon.aspx ページにリダイレクトされます。この構成を変更することで、特定のユーザーやグループだけにアプリケーションへのアクセスを許可することができます。

Web.config ファイルを変更するには

  1. メモ帳で Web.config を開きます。

  2. 既存のコードを次のコードで置換します。

    <?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>
    

次の configuration 要素に注目してください。

<identity impersonate="true"/>

この要素により、ASP.NET は、Microsoft インターネット インフォメーション サービス (IIS) の匿名のアカウントとして構成されるアカウントを偽装します。この構成の結果として、このアプリケーションに対するすべての要求が、構成されたアカウントのセキュリティ コンテキストの下で実行されます。ユーザーは、Active Directory ドメイン サービスに対して認証する資格情報を提供しますが、Active Directory ドメイン サービスにアクセスするアカウントは、構成されたアカウントです。

匿名認証用に IIS を構成するには

  1. (管理ツールの) IIS マネージャまたは IIS 用の MMC スナップインで、認証を構成する Web サイトを右クリックして、[プロパティ] をクリックします。

  2. [ディレクトリ セキュリティ] タブをクリックして、次に [認証とアクセス制御] の下の [編集] をクリックします。

  3. [匿名認証] チェックボックスをオンにします (Windows Server 2003では [匿名アクセスを有効にする] というラベルが付いています)。

  4. アプリケーションの匿名アカウントを、Active Directory ドメイン サービスへのアクセス許可を持つアカウントにします。

  5. [IIS によるパスワードの管理を許可する] チェックボックスが存在する場合は、これをオフにします。既定の IUSR*_<コンピュータ名>* アカウントには、Active Directory ドメイン サービスへのアクセス許可がありません。

Logon.aspx ページを作成するには

  1. [ソリューション エクスプローラ] で、プロジェクト ノードを右クリックして、[追加] をポイントし、[Web フォームの追加] をクリックします。

  2. [名前] ボックスに、「Logon.aspx」と入力して、[開く] をクリックします。.

  3. [ソリューション エクスプローラ] で、[Logon.aspx] を右クリックして、[デザイナの表示] をクリックします。

  4. デザイナ[HTML] タブをクリックします。

  5. 既存のコードを次のコードで置換します。

    <%@ Page language="c#" AutoEventWireup="true" %>
    <%@ Import Namespace="FormsAuth" %>
    <html>
      <body>
        <form id="Login" method="post" runat="server">
          <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. Logon.aspx ページのパスを変更して、LDAP ディレクトリ サーバーを指定します。

Logon.aspx ページは、ユーザーから情報を収集し、LdapAuthentication クラスのメソッドを呼び出すページです。このコードは、ユーザーの認証を行い、グループの一覧を取得した後、FormsAuthenticationTicket オブジェクトを作成し、チケットを暗号化し、暗号化したチケットを Cookie に追加し、Cookie を HttpResponse.Cookies コレクションに追加した後、最初に要求された URL に要求をリダイレクトします。

WebForm1.aspx ページは、最初に要求されるページです。ユーザーがこのページを要求すると、その要求は Logon.aspx ページにリダイレクトされます。要求の認証が行われると、その要求は WebForm1.aspx ページにリダイレクトされます。

WebForm1.aspx ページを変更するには

  1. [ソリューション エクスプローラ] で、[WebForm1.aspx] を右クリックして、[デザイナの表示] をクリックします。

  2. デザイナ[HTML] タブをクリックします。

  3. 既存のコードを次のコードで置換します。

    <%@ Page language="c#" AutoEventWireup="true" %>
    <%@ Import Namespace="System.Security.Principal" %>
    <html>
      <body>
        <form id="Form1" method="post" runat="server">
          <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. すべてのファイルを保存して、プロジェクトをコンパイルします。

  5. WebForm1.aspx ページを要求します。Logon.aspx にリダイレクトされることに注意してください。

  6. ログオン資格情報を入力して、[送信] をクリックします。WebForm1.aspx にリダイレクトされると、ユーザー名が表示され、LdapAuthentication が Context.User.AuthenticationType プロパティに対応する認証の種類になっていることに注意してください。

ms180890.note(ja-jp,VS.90).gifメモ :
フォーム認証を使用する際には、Secure Sockets Layer (SSL) の暗号化を使用することをお勧めします。これは、ユーザーが認証 Cookie に基づいて識別されており、このアプリケーションに SSL の暗号化を適用することで、認証 Cookie や送信されるその他の重要な情報が危険にさらされることを防止するためです。

関連項目

リファレンス

System.DirectoryServices
DirectoryEntry
DirectorySearcher

概念

高度なプログラミングのトピック

Send comments about this topic to Microsoft.

Copyright © 2007 by Microsoft Corporation. All rights reserved.