web-dev-qa-db-ja.com

フォーム認証を使用して偽装する

ActiveDirectoryMembershipProviderにアクセスするためにWindows認証ではなくフォーム認証を使用する必要があるASP.NETサイトがあります。 Windows認証で使用されるブラウザー認証ポップアップではなく、設計された入力フォームが必要なため、サイトではフォームを使用する必要があります。

サイトは、ユーザー固有のファイルにアクセスするために、ActiveDirectoryを介してログインしたユーザーになりすます必要があります。

ただし、私のweb.configには次のものが含まれていますが、WindowsIdentity.GetCurrent()は_HttpContext.Current.User.Identity_と同じではありません。

_<authentication mode="Forms">
    <forms loginUrl="login.aspx" timeout="480"/>
</authentication>
<identity impersonate="true" />
_

LoginUser()WindowsIdentity.Impersonate()を使用できません。これは、特定の権限を取得するためにADユーザーになりすます必要があり、Formsがログインを処理するため、ユーザーのパスワードがわからないためです。 。

Login.aspx.csから_System.Web.UI.WebControls.Login.Password_を取得し、後でLoginUser()のセッション変数にWindowsIdentity.Impersonate()トークンを保存することは可能ですか?それとも、正しい方法で偽装するはるかに安全な方法ですか?

フォーム認証が自動的にできない理由がわかりません_<identity impersonate="true" />_

私はこれを読みました http://msdn.Microsoft.com/en-us/library/ms998351.aspx しかし、それはWindows認証を使用します。

25
Robert

フォーム認証を使用してユーザーになりすますことができます。次のコードは機能します

Visual Studio Magazineの記事 Robertが参照しているのは優れたリソースです。この記事のサンプルコードにはいくつかの問題があるため、以下にいくつかの実用的なコードを含めました。

注:Visual Studioを使用している場合は、UACによる偽装のブロックの問題を回避するために、必ず「管理者として実行」を起動してください。

_// in your login page (hook up to OnAuthenticate event)
protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e)
{
    int token;
    // replace "YOURDOMAIN" with your actual domain name
    e.Authenticated = LogonUser(LoginUser.UserName,"YOURDOMAIN",LoginUser.Password,8,0,out token);
    if (e.Authenticated) {
        Session.Add("principal", new WindowsPrincipal(new WindowsIdentity(new IntPtr(token))));
    }
}

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword,
    int dwLogonType, int dwLogonProvider, out int TokenHandle);


// in global.asax.cs
void Application_PreRequestHandlerExecute(object send, EventArgs e)
{
    if (Thread.CurrentPrincipal.Identity.IsAuthenticated == true && HttpContext.Current.Session != null) {
        WindowsPrincipal windowsPrincipal = (WindowsPrincipal)Session["principal"];
        Session["principal"] = (GenericPrincipal)Thread.CurrentPrincipal;
        Thread.CurrentPrincipal = windowsPrincipal;
        HttpContext.Current.User = windowsPrincipal;
        HttpContext.Current.Items["identity"] = ((WindowsIdentity)windowsPrincipal.Identity).Impersonate();
    }
}

// in global.asax.cs
void Application_PostRequestHandlerExecute(object send, EventArgs e)
{
    if (HttpContext.Current.Session != null && Session["principal"] as GenericPrincipal != null) {
        GenericPrincipal genericPrincipal = (GenericPrincipal)Session["principal"];
        Session["principal"] = (WindowsPrincipal)Thread.CurrentPrincipal;
        Thread.CurrentPrincipal = genericPrincipal;
        HttpContext.Current.User = genericPrincipal;
        ((WindowsImpersonationContext)HttpContext.Current.Items["identity"]).Undo();
    }
}

// test that impersonation is working (add this and an Asp:Label to a test page)
protected void Page_Load(object sender, EventArgs e)
{
    try {
        // replace YOURSERVER and YOURDB with your actual server and database names
        string connstring = "data source=YOURSERVER;initial catalog=YOURDB;integrated security=True";
        using (SqlConnection conn = new SqlConnection(connstring)) {
            conn.Open();
            SqlCommand cmd = new SqlCommand("SELECT SUSER_NAME()", conn);
            using (SqlDataReader rdr = cmd.ExecuteReader()) {
                rdr.Read();
                Label1.Text = "SUSER_NAME() = " + rdr.GetString(0);
            }
        }
    }
    catch {
    }
}
_

更新:

Response.End()のような呼び出しは_Application_EndRequest_をバイパスするため、_Application_PostRequestHandlerExecute_も処理する必要があります。

もう1つの問題は、WindowsIdentityがガベージコレクションを取得する可能性があるため、要求ごとにログオントークンから新しいWindowsIdentityとWindowsPrincipalを作成する必要があることです。

Update2:

それが機能するので、なぜこれが反対票を投じられているのかわかりません。 pinvoke署名といくつかのテストコードを追加しました。ここでも、「管理者として実行」を使用してVisualStudioを起動します。あなたが方法を知らないならば、グーグルはそれをする方法。

20
user281806

あなたはこれが役に立つと思うかもしれません:

[〜#〜]編集[〜#〜]

あなたの質問をもっと詳しく読んでみると、そのアプローチがあなたのシナリオでうまくいくかどうかはわかりません。フォーム認証を使用してログインし、ActiveDirectoryユーザーを偽装する場合

0
kristof

最近同じ問題が発生しました。顧客はユーザーがADアカウントでログインできることを望んでおり、この資格情報を使用してAnalysisServiceや他のすべてのデータベースにアクセスする必要があります。彼らは監査システムを実装し、すべてのアクセスは現在ログインしているアカウントで行う必要があるため、そのように望んでいました。

パーツを偽装するためにフォーム認証とWin32LogonUser()APIを試しましたが、機能しましたが、プレーンテキストとしてユーザーのパスワードも要求されます。その後、Windows認証を利用することにしました。これにより、時間を大幅に節約できます(AD認証が不要になり、手動で偽装できます)。もちろん、派手なログインページもありませんでした。

0
Tien Do

ユーザーがIEを使用している場合は、Webサイトの統合セキュリティをオンにすると、ユーザーはサイレントに認証されます(ログインダイアログなし、ログインページなし)。その後、偽装が機能します。他のブラウザをターゲットにする必要がある場合、これは機能しない可能性があります(ユーザーにはおそらくログインダイアログが表示されます)。

ユーザーがドメインアカウント以外のアカウントを使用してログインしているため、現在の偽装は機能しません。資格情報を提供していないユーザーになりすますサイトを期待することはできません。それは基本的なセキュリティプリンシパルに反します。

0
Adam Ralph