20

ここ数日間、私は Windows ID 基盤について読んでいて、それがいかに優れていて柔軟性があり、.net 4.5 に組み込まれているのかについて読んでいました。何十ものAPI、ブログ投稿、ハウツーなどを調べたにもかかわらず、私の人生では簡単な実装を機能させることはできません。

私は Windows 認証のみを使用しており、プリンシパルを取得してそれに付随するクレームを表示できます (すべての例が終了するようです)。ただし、それらを有用なクレームに変換し、結果をキャッシュして、すべてのリクエストで変換が行われないようにしたいと考えています。

私のweb.configには次のものがあります:

  <configSections>
    <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
  </configSections>

  <system.identityModel>
    <identityConfiguration>
      <claimsAuthenticationManager type="SecurityProj.MyClaimsTransformationModule,SecurityProj" />
      <claimsAuthorizationManager type="SecurityProj.MyClaimsAuthorizationManager,SecurityProj" />
    </identityConfiguration>
  </system.identityModel>

ただし、認証マネージャーが呼び出されることはありません。私がそれをある種の仕事に導くことができる唯一の方法は、追加することです:

protected void Application_PostAuthenticateRequest()
{
    ClaimsPrincipal currentPrincipal = ClaimsPrincipal.Current;
    ClaimsTransformationModule customClaimsTransformer = new MyClaimsTransformationModule();
    ClaimsPrincipal tranformedClaimsPrincipal = customClaimsTransformer.Authenticate(string.Empty, currentPrincipal);
    HttpContext.Current.User = tranformedClaimsPrincipal;
}

私のglobal.asax.csファイルに。最初のリクエストでは機能しますが、その後「安全なハンドルが閉じられました」というエラーが発生し、何が原因なのかわかりません。明らかにこれは正しい方法ではないので、ベストプラクティスまたは単純な作業プラクティスを知っている人はいますか? これは Windows 認証のためだけのものです。それ以上複雑なものは必要ありません。

キャッシングのために、私は使用しようとしていました:

        SessionSecurityToken token = FederatedAuthentication.SessionAuthenticationModule
            .CreateSessionSecurityToken(
            currentPrincipal,
            "Security test",
            System.DateTime.UtcNow,
            System.DateTime.UtcNow.AddHours(1),
            true);

        if (FederatedAuthentication.SessionAuthenticationModule != null &&
            FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
        {
            return;
        }
        FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(token);

しかし、その部分についてもよくわかりません。変換の問題を最初に修正する必要があります。

どんな助けでも大歓迎です。ルックアップ/変換を呼び出す必要があり、Cookie セットが必要です。

4

2 に答える 2

19

私は今、すべてが機能しています。これが私が行った方法です:

このページ: http://msdn.microsoft.com/en-us/library/ee517293.aspx重要な段落:

RP アプリケーションをクレーム対応にしたいが、STS を持っていない (たとえば、RP がフォーム認証または Windows 統合認証を使用している) 場合は、ClaimsPrincipalHttpModule を使用できます。このモジュールはアプリケーションの HTTP パイプラインにあり、認証情報をインターセプトします。各ユーザーのユーザー名、グループ メンバーシップ、およびその他の認証情報に基づいて、各ユーザーの IClaimsPrincipal を生成します。ClaimsPrincipalHttpModule は、IIS 7のセクションの<httpModules>最初の要素であるパイプラインの最後に挿入する必要があります。<modules><system.webServer>

そしてこのページ:

http://leastprivilege.com/2012/04/04/identity-in-net-4-5part-2-claims-transformation-in-asp-net-beta-1/

クラス全体を提供します:

public class ClaimsTransformationHttpModule : IHttpModule
{
    public void Dispose()
    { }

    public void Init(HttpApplication context)
    {
        context.PostAuthenticateRequest += Context_PostAuthenticateRequest;
    }

    void Context_PostAuthenticateRequest(object sender, EventArgs e)
    {
        var context = ((HttpApplication)sender).Context;

        // no need to call transformation if session already exists
        if (FederatedAuthentication.SessionAuthenticationModule != null &&
            FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(context.Request.Cookies))
        {
            return;
        }

        var transformer =
        FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
        if (transformer != null)
        {
            var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, context.User as ClaimsPrincipal);

            context.User = transformedPrincipal;
            Thread.CurrentPrincipal = transformedPrincipal;
        }
    }
}

そのクラスを web.config に追加します。

<modules>
  <add name="ClaimsTransformationHttpModule" type="TestSecurity.ClaimsTransformationHttpModule" />
</modules>

これで変換が呼び出され、global.asax で認証後のメソッドを削除できます。

認証メソッドでは、これを呼び出して Cookie を設定します。

private void CreateSession(ClaimsPrincipal transformedPrincipal)
{
    SessionSecurityToken sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
    FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
}

前のモジュールは、それを見て、存在する場合は認証をスキップするように既に設定されています。

最後に、ずっと発生していたセーフ ハンドル エラーについてです。原因は正確にはわかりませんが、Authenticate に渡されるプリンシパルを変更してから返すと (msdn に表示されます)、後続のすべての要求でエラーが表示されることがわかりました。ただし、新しいプリンシパルを作成して返した場合、それは発生しません。これは、不要なクレームを削除する場合にも役立ちます。

List<Claim> newClaims = new List<Claim>();

var keeper = ((ClaimsIdentity)incomingPrincipal.Identity).Claims.First(c =>
    c.Type == ClaimTypes.Name);
newClaims.Add(keeper);

ClaimsIdentity ci = new ClaimsIdentity(newClaims, "Negotiate");

return new ClaimsPrincipal(ci);

これで、Windows 認証を行い、カスタム クレームを取り込み、それらを Cookie でキャッシュできるようになりました。これが同じことをしようとしている他の人に役立つことを願っています。私が何か正しいことをしていない場合はお知らせください。

于 2013-06-06T18:52:25.387 に答える
11

この回答は、いくつかの同様の問題を解決しようとしてイライラする日々を経験した後、上記のジョンの回答をさらに明確にすることを目的としています。

1. ClaimsPrincipalHttpModule

John が発見したように、Windows 認証またはフォーム認証を使用している場合、ASP.NET は自動的に ClaimsAuthenticationManager を呼び出しません (フェデレーション シナリオではありません)。ASP.NET がユーザーを認証した後、自分で行う必要があります。以前は IdentityModel の一部であった ClaimsPrincipalHttpModule を使用すると、これが効果的に確実に行われます。

ただし、このモジュールの使用には注意してください。理由により削除されました。IdentityModel から削除された理由についての私の理論は、ASP.NET アプリで WCF サービスをホストし、aspNetCompatibilityEnabled=true を設定している場合、うまく動作しないためです。これにより、WCF 認証が壊れます (モジュールは WCF パイプラインの前に実行され、私の経験では、WCF クライアントは適切に認証できなくなります - Windows 認証を使用するときにこれを確認しました)。

このシナリオで WCF サービスをホストしている場合は、ClaimsAuthenticationManager が非 WCF 要求に対してのみ呼び出されるようにする必要があります。WCF リクエストの場合は、WCF パイプラインに依存する必要があるようです ( <serviceCredentials useIdentityConfiguration="true" />)。最も簡単な解決方法は、単に aspNetCompatibilityEnabled をオフにすることです。これがオプションでない場合は、ClaimsPrincipalHttpModule を使用するべきではありませんが、何らかの方法で着信要求を調べ、要求が WCF 宛てでない場合にのみ ClaimsAuthenticationManager を呼び出す必要があります。

2. セーフ ハンドル エラー (ObjectDisposedException)

これは、WindowsIdentity に基づく SessionSecurityToken を作成した場合に発生します。SessionAuthenticationModule には、SessionSecurityToken から読み取られた WindowsIdentity クレームを処理する特別なロジックがあり、有効ではなくなったデータを使用して WindowsIdentity の復元を試みます。(どのような状況で機能するかはわかりませんが、テストしたすべてのシナリオで一貫して失敗しました)。したがって、John が説明したように、ここでの教訓は、Windows 認証で WIF を使用しようとする場合、SessionSecurityTokens を WindowsPrincipal (より正確には WindowsIdentity) から作成してはならないということです。他のタイプの変換された ClaimsPrincipal は問題ありません。

于 2013-12-31T04:56:26.597 に答える