WCF Sample 012その1 httpsを使用してWCFサービスをIIS7.0上で公開する では、httpsを使用して、WCFを公開する方法を掲載しました。今回はユーザ認証、アクセス制御にSqlMembershipProvider,SqlRoleProviderを使用するようにサービスの構成を変更し、クライアントからアクセスします。最後に、WCF Sample 011  と同じようにサービスへのアクセス許可を制御するサンプルを掲載します。ただし、アクセスを許可するロールはWindowsTokenRoleProviderではなく、SqlRoleProviderから制御されます。

動作確認環境

  • Windows Vista Enterprise(スタンドアロン: IIS7.0からWCFサービスを公開する。WCFクライアントはコンソールアプリ)
  • 開発環境 Visual Studio 2008 Enterprise
  • .NET 3.5

0.前提条件

前提条件として、SqlMembershipProvider,SqlRoleProviderは使用できる構成がWCFSample012ProductServiceプロジェクトのWeb.configに作成済みであるとします。構成の仕方が不明の場合は説明のあるMSDNや書籍、Webサイトを参考にして下さい。次のユーザがデータベースに登録されているとします。

 

ユーザ名 AspWcfUser
パスワード AspWcfUser001
ロール AspWcfUsers

 

Membershipプロバイダ名はAspNetSqlMembershipProvider, Roleプロバイダ名はAspNetSqlRoleProviderで構成されているとします。

1.WCFサービスがSqlRoleProviderとSqlMembershipProviderを使用するように構成する

 資格情報,ロール情報にSqlMembershipProviderとSqlRoleProviderを使用するように構成します。

WCFSample012ProductServiceプロジェクトのWeb.configをWCF Service Configuration Editorで編集します。左側ペインの[Advanced]→[Service Behavior]→ProductServiceBehaviorを選択し、右側ペインの[Add]ボタンをクリックし、表示されるAdding Behavior Element Extention SectionsダイアログからserviceAuthorizationとserviceCredentialsを選択して[Add]ボタンクリックしてBehaviorを追加する。

 

 

 左側ペインの追加されたserviceAuthorizationを選択する。右ペインのPrincipalPermissionModeをUseWindowsGroupsからUseAspNetRolesとし、RoleProviderNameにAspNetSqlRoleProviderとします。この設定でユーザの所属するロールの情報としてWindowsのセキュリティグループではなくMemberShipPvoviderのロール情報を使用するようになります。

AspNetSqlRoleProviderはmachine.configに定義されているデフォルトのプロバイダ名ですが、connectionStringNameがLocalSqlServerではないなど、プロバイダの構成に変更が必要な場合はWeb.configで再定義する必要があります。下記例参照

    定義例:
    <roleManager enabled="true" defaultProvider="AspNetSqlRoleProvider">
       <providers>
          <clear/>
            <add name="AspNetSqlRoleProvider" connectionStringName="AspNetSqlConnection" applicationName="/" 
                 type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
       </providers>
    </roleManager>

 

 

 

次に、追加されたserviceCredentialsを選択し、右側ペインのUserNamePasswordValidationModeをMembershipProviderにセットし、MembershipProviderNameにAspNetSqlMembershipProviderを指定します。この設定によりユーザの認証にWindowsのユーザではなくMembershipProviderのユーザを使用するようになります。

AspNetSqlMembershipProviderはmachine.configに記載されているSqlMembershipProviderを使用するMembershipProviderの設定です。connectionStringNameがLocalSqlServerではないなどプロバイダの設定に変更がある場合はWeb.configで再定義します。以下設定例

    <membership defaultProvider="AspNetSqlMembershipProvider">
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, 
       Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="AspNetSqlConnection" 
       enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" 
       applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" 
       minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" 
       passwordStrengthRegularExpression=""/>
      </providers>
    </membership>

 

 

変更内容を上書き保存して、Configuration Editorを終了します。

 2.WCFクライアントの作成

2.1 App.configの構成を変更

WCFSample.ConsoleClientのApp.configをWCF Service Configuration Editorで編集します。左のペインのBindingsを右クリックし新規作成します。最初に表示されるダイアログでwsHttpBindingを選択して[OK]をクリックします。右側ペインのNameをWSHttpBinding_ProductServiceにします。SerucityタブをクリックしてModeをWCFサービスと同じTransportWithMessageCredentialに設定し、MessageClientCredentialTypeをUserNameにセットし、TransportClientCredentialTypeをNoneに設定します。

 

 

左側ペインのClient→Endpoints→BasicHttpBinding_ProductServiceを選択。右側ペインのBindingにwsHttpBindingを選択し、BindingConfigurationにWSHttpBinding_ProductServiceを選択する。Addressにhttps://localhost/WCFSample012/ProductService.svcを入力します。変更内容を保存して終了します。

2.2 クライアントプログラムの修正

WCFSample.ConsoleClientのProgram.csを変更します。SSLで使用する証明書は信頼されていない証明期間(自己証明書)から発行されているので、証明書に問題がある場合も、確認メッセージを表示して処理を続行するかを決めるクラスを追加します。

/// <summary>
    /// 証明書に問題がある場合は確認するポリシークラス
     /// </summary>
    class ConfirmCertificatePolicy
    {
        public ConfirmCertificatePolicy()
        {
            ServicePointManager.ServerCertificateValidationCallback += RemoteCertValidation;
        }
        bool RemoteCertValidation(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
        {
            if (error != SslPolicyErrors.None)
            {
                Console.WriteLine("証明書に問題があります。理由:" + chain.ChainStatus[0].StatusInformation);
                Console.Write("処理を続行しますか? y:続行:");
                string input = Console.ReadLine();
                if (input.ToLower() == "y")
                    return true;
                else
                    return false;
            }
            return true;
        }
    }

 次に、Mainメソッドの最初にConfirmCertificatePolicyクラスのインスタンスを作成するコードを追加し、サービスメソッドを呼び出す前にプロキシクラスにユーザの資格情報を入力するコードを追加します。

static void Main(string[] args)
        {
            ConfirmCertificatePolicy policy = new ConfirmCertificatePolicy(); // 証明書続行確認用
            System.Console.WriteLine("WCFサービスホストを起動したら、キーを入力して下さい。");
            System.Console.ReadLine();

            ProductServiceClient proxy = new WCFSample.Client.Proxy.ProductServiceClient("BasicHttpBinding_ProductService");
            proxy.ClientCredentials.UserName.UserName = "AspWcfUser";     // ユーザID
            proxy.ClientCredentials.UserName.Password = "AspWcfUser001";  // パスワード
            int[] productIDs = proxy.GetProductIDs();

            foreach (int productID in productIDs)
            {
                Console.WriteLine("Product ID: " + productID);
                Product product = proxy.GetProductByID(productID);
                Console.WriteLine("Name: " + product.Name);
                Console.WriteLine("Color: " + product.Color);
                Console.WriteLine("ListPrice: " + product.ListPrice);

            }
            proxy.Close();

            Console.WriteLine("終了するにはなにかキーを押してください。");
            Console.ReadLine();
        }

以上で修正は完了です。

スタートアッププロジェクトにWCFSample.ConsoleClientを指定してデバッグ実行を行うと、コンソールに証明書が不正で続行するかの確認メッセージが表示されます。yを入力するとプログラムが続行されます。

3.サービスメソッドにアクセス制御を設定する

PrincipalPermissionAttributeを使用している場合は、Windowsのセキュリティグループを使用している場合と同じで次のようにサービスクラスのサービスメソッドに属性を付与します。以下の例はGetProductIDs()サービスメソッドのアクセス可能なロールにAspWcfUsersを指定する場合。

        [PrincipalPermission(SecurityAction.Demand, Role = "AspWcfUsers")]
        public List<int> GetProductIDs()
        {..}

同様の処理をサービスメソッド内で行い場合は以下のように記述します。

        public List<int> GetProductIDs()
        {
            IIdentity user = System.ServiceModel.ServiceSecurityContext.Current.PrimaryIdentity;
            if (!(System.Web.Security.Roles.IsUserInRole("AspWcfUsers")))
            {
                throw new System.Security.SecurityException("Access Denied");
            }
         ..
        }