WCF のトランスポート レベル セキュリティー (Basic 認証など) で カスタムな認証をおこなう


環境:
Visual Studio 2008

.NET Framework 3.5 セキュリティ / 認証あれこれ

こんにちは。

だいぶ間が空いてしまいましたが、今日は、WCF の認証について .NET Framework 3.5 で追加された仕組みを説明します。が、その前に、まず、既存の WCF (.NET Framework 3.0) がどうであったかという点をおさらいしておきましょう。(尚、ここでは、「認証」の切り口のみでおさらいしていますが、WCF のセキュリティ全般で言えば、暗号化や、特定のメソッドなどを特定のユーザだけに使わせるロール的な考え方など、Integrity, Confidentiality, Authorization といったさまざまな観点での考え方が含まれていて、必要におうじて利用することができるようになっています。)

WCF では、 以下の認証が可能となっていますが、それぞれに「トランスポート レベル」 (Transport level) と、「メッセージ レベル」 (Message Level) という考え方があり、認証のタイプによっては、どちらか一方のみしか使えないようになっています。
ざっくりとした書き方ですが、トランスポート レベルとは、TCP や HTTP などのネットワーク プロトコルの層でおこなわれる認証で、メッセージ レベルとは、その上位の層、例えば、SOAP のタグ付きメッセージのコンテンツそのもの、などを使って認証の仕組みを実現しています。ですから、トランスポート レベルだと、既存の TCP や HTTP が持つ一般的なセキュリティの機構をそのまま使うことができますが、メッセージ レベルでは、その上のメッセージの仕様如何でさまざまな方式やルールを定義できるため、より柔軟なセキュリティの仕組みを実装することができるようになっています。

以下に、WCF の認証について整理をおこない、さいごに、今回の .NET 3.5 における新機能を説明します。

1. None

クライアントは、Credential を必要としません。(いわゆる、匿名アクセスをおこないたい場合に、下記の通り構成します。)

  [config の構成例]
  ...
  <security mode="None"/>
  ...

2. Basic (トランスポート レベルのみ)

クライアントは ID, パスワードを指定して接続する必要があります。(ユーザID, パスワードは、ダイアログボックスなどでユーザに入力を促すことになるでしょう。)
このID, パスワードは、既存の Basic 認証の仕組みを使用してクリアテキスト(ただし、通常はアルゴリズムによりエンコードされます)でヘッダーに設定されて渡されます。

  [config の構成例]
  ...
  <security mode="TransportCredentialOnly">
    <transport clientCredentialType="Basic" />
  </security>
  ...

上記では暗号化をおこなわず、認証のみをトランスポート モードとしていますが、HTTPS (SSL) を使う場合には、mode を Transport とします。

3. Digest (トランスポート レベルのみ)

Basic と同様ですが、クリアテキストではなく、複合化が困難な一方向暗号化 (と書くと意味不明ですね。クライアントで暗号化されて、サーバに渡されます。サーバ側では複合化せず、同一性の照合のみをおこないます) が使用されます。
いわゆる Digest 認証と呼ばれる方式です。

  [config の構成例]
  ...
  <security mode="TransportCredentialOnly">
    <transport clientCredentialType="Digest" />
  </security>
  ...

3. Windows (トランスポート レベル / メッセージ レベル)

トランスポート レベルで指定すると、通常の Windows 認証のプロトコルのように、SSPI (Security Support Provider Interface) を使った Windows 認証をおこないます (その際、通常は、Kerberos が使用されます)。
また、メッセージ レベルで指定すると、SOAP メッセージ交換の credential として、Windows の認証情報を使用します。
クライアント側では、認証情報は、クライアント側で使用されている Windows 認証の内容 (ドメインでのログインユーザの内容) が自動的に使用されることになります。(無論、クライアント側の .config に、Windows 認証を使うように指定をしておきましょう。)

  [config の構成例]
  ...
  <security mode="Transport">
    <transport clientCredentialType="Windows" />
  </security>
  ...

  または

  ...
  <security mode="Message">
    <transport clientCredentialType="Windows" />
  </security>
  ...

4. Certificate (トランスポート レベル / メッセージ レベル)

この指定も、トランスポート レベルとメッセージ レベルで使用可能です。
トランスポートレベルで使用すると、SSL over HTTP, もしくは SSL over TCP によりトランスポート レベルでの機密性を確保できます。
メッセージ レベルで使用すると、SOAP メッセージセキュリティに準じて、証明書によるSOAP メッセージの暗号化と署名がおこなわれます。メッセージ レベルでは、SOAP の柔軟な規程により、トランスポート セキュリティ機構だけでは実現できない資格情報が提供可能です。
使用する証明書は、クライアント側の .config に記述します。(あるいは動的に指定したい場合は、コードで、クライアント クラスの ClientCredentials.ClientCertificate.SetCertificate メソッドを使います。)

  [config の構成例]
  ...
  <security mode="Transport">
    <transport clientCredentialType="Certificate" />
  </security>
  ...

  または

  ...
  <security mode="Message">
    <transport clientCredentialType="Certificate" />
  </security>
  ...

5.UserName (メッセージ レベル)

上述の Basic や Digest のように、クライアントは明示的なユーザIDとパスワードの指定が必要です。ただし、Basic, Digest と違い、トランスポートレベルでなく、SOAP メッセージ交換の credential としてメッセージレベルで処理されます。

  [config の構成例]
  ...
  <security mode="Message">
    <transport clientCredentialType="UserName" />
  </security>
  ...

6. IssuedToken (メッセージ レベル)

Windows CardSpace という .NET Framework 3.0 からの新しいアイデンティティフレームワークを使用して認証をおこないます。
Windows CardSpace を使ったデモや構成の記述については、

http://www.microsoft.com/japan/msdn/windows/windowsserver2008/tab/code/wcs.aspx

を参照してください。

 

上記の Basic, Digest, UserName ではユーザID とパスワードによる認証をおこなうと記載しましたが、どこの入れ物で「ユーザID」と「パスワード」を管理するのか疑問に思われるかもしれません。.config などで何の指定もしないと、通常は、(ドメインの) Windows Identity の情報が使用されます。ですので、クライアント側では、接続時にドメインユーザIDとパスワードを指定して接続することになります。

しかし、メッセージレベルの UserName では、さらに柔軟な構成が可能です。UserName では、userNamePasswordValidationMode 属性というものを使用すると、例えば、MembershipProvider と指定すると ASP.NET のメンバーシップデータベースを使うことができたり、Custom を指定すると独自の認証処理をコードで記述 (アセンブリとしてコンパイル) して使用したり、といった、カスタムな認証を実現することが可能になっています。

 

そして、.NET Framework 3.5 の新機能

と、だいぶ前置きが長くなりましたが (すみません、ほとんど前置きになりました)、Visual Studio 2008 からの .NET Framework 3.5 では、カスタムの認証が、メッセージレベルだけでなく、トランスポートレベルでも使用できるようになっています。(これが、今日の本旨です。) .config やカスタムのユーザー名/パスワード検証コントロールの書き方は、概ね UserName のときと同様、以下のような感じです。

下記は、Basic 認証で、ユーザー ID / パスワード としてメンバーシップ (Membership) プロバイダーを使用した場合の構成例です。

<?xml version="1.0"?>
<configuration>

  <connectionStrings>
    <add name="SqlConn"
         connectionString="Data Source=myserversqlexpress;Initial Catalog=aspnetdb;User Id=testuser;Password=XXXXXXX"/>
  </connectionStrings>

  <system.web>
    <membership defaultProvider="SqlMemProvider"
                userIsOnlineTimeWindow="15">
      <providers>
        <clear />
        <add
          name="SqlMemProvider"
          type="System.Web.Security.SqlMembershipProvider"
          connectionStringName="SqlConn"
          applicationName="MembershipAndRoleProviderSample"
          enablePasswordRetrieval="false"
          enablePasswordReset="false"
          requiresQuestionAndAnswer="false"
          requiresUniqueEmail="false"
          passwordFormat="Hashed" />
      </providers>
    </membership>
  </system.web>

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceCredentials>
            <userNameAuthentication
              userNamePasswordValidationMode="MembershipProvider"
              membershipProviderName="SqlMemProvider"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
   
    <bindings>
      <basicHttpBinding>
        <binding name="MyBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Basic"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>

    <services>
      <service name="ConsoleApplication1.Service1"
               behaviorConfiguration="MyBehavior">
        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="ConsoleApplication1.IService1"
                  bindingConfiguration="MyBinding">
        </endpoint>
      </service>
    </services>
  </system.serviceModel>

</configuration>

メンバーシップ プロバイダーを使わず、まったく独自のユーザー管理をおこなう場合には、独自の UserNamePasswordValidator クラスを作成して、以下の通り構成します。(これまでの、メッセージ レベルのセキュリティと、何ら変わりありません。)

. . .
<system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyBehavior">
          . . .
          <serviceCredentials>
            <userNameAuthentication
              userNamePasswordValidationMode="Custom"
              customUserNamePasswordValidatorType="作成したクラスの厳密名 . . ."/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    . . .

さいごに、一点、注意点があります。
上記のように、カスタムのプロバイダーを使用した場合、IIS にホストすると、IIS のパイプラインにおける Basic 認証が効いてしまい、うまく つながりません。(厳密には、IIS の Basic 認証が効いているため、Windows Identity が使用されます。)  このため、上記では、コンソール アプリケーションなど、セルフ ホスト (seif-host) を使って WCF サービスを動かしてください。

補足 : IIS のパイプライン上で、上記のように、メンバーシップや、カスタムの Identity 管理と連携して、Basic 認証を使用したい場合、以下が使用できます。

[CodePlex] Custom Basic Authentication for IIS :
http://custombasicauth.codeplex.com/

 

Comments (2)

  1. 環境: Visual Studio 2008 こんにちは。 だいぶ間が空いてしまいましたが、今日は、WCF の認証について .NET Framework 3.5 で追加された仕組みを説明します。が、その前に

  2. 環境: Visual Studio 2008 部分信頼アプリケーションからの WCF の利用 トランスポートレベルのカスタムな認証 クライアントアプリケーションサービス こんにちは。 メインタイトルの前に余計な帯をつけたのは、この切り口でいくつかノウハウを掲載しようと思ったためです。今日は、.NET

Skip to main content