Bagikan melalui


Kebijakan Otorisasi

Sampel ini menunjukkan cara menerapkan kebijakan otorisasi klaim kustom dan pengelola otorisasi layanan kustom terkait. Sampel tersebut berguna pada saat layanan melakukan pemeriksaan akses berbasis klaim untuk operasi layanan, dan sebelum pemeriksaan akses untuk memberikan hak tertentu kepada pemanggil. Sampel ini menunjukkan proses penambahan klaim serta proses untuk melakukan pemeriksaan akses terhadap serangkaian klaim yang diselesaikan. Semua pesan aplikasi antara klien dan server ditandatangani dan dienkripsi. Secara default dalam pengikatanwsHttpBinding, nama pengguna dan kata sandi yang disediakan oleh klien digunakan untuk masuk ke akun Windows yang valid. Sampel ini menunjukkan cara menggunakan UserNamePasswordValidator kustom untuk mengautentikasi klien. Selain itu, sampel ini menunjukkan klien yang mengautentikasi ke layanan menggunakan sertifikat X.509. Sampel ini menunjukkan implementasi IAuthorizationPolicy dan ServiceAuthorizationManager, yang di antaranya memberikan akses ke metode layanan tertentu untuk pengguna tertentu. Sampel ini didasarkan pada Nama Pengguna Keamanan Pesan, tetapi menunjukkan cara melakukan transformasi klaim sebelum ServiceAuthorizationManager dipanggil.

Catatan

Prosedur penyiapan dan petunjuk pembuatan untuk sampel ini terdapat di akhir topik ini.

Singkatnya, sampel ini menunjukkan cara:

  • Klien dapat diautentikasi menggunakan nama pengguna-kata sandi.

  • Klien dapat diautentikasi menggunakan sertifikat X.509.

  • Server memvalidasi mandat klien berdasarkan validator UsernamePassword kustom.

  • Server diautentikasi menggunakan sertifikat X.509 server.

  • Server dapat menggunakan ServiceAuthorizationManager untuk mengontrol akses ke metode tertentu dalam layanan.

  • Cara implementasi IAuthorizationPolicy.

Layanan ini mengekspos dua titik akhir untuk berkomunikasi dengan layanan, yang ditentukan menggunakan file konfigurasi App.config. Setiap titik akhir terdiri dari alamat, pengikatan, dan kontrak. Satu pengikatan dikonfigurasi dengan pengikatan wsHttpBinding standar yang menggunakan WS-Security dan autentikasi nama pengguna klien. Pengikatan lainnya dikonfigurasi dengan pengikatan wsHttpBinding standar yang menggunakan WS-Security dan autentikasi sertifikat klien. <Perilaku> menentukan bahwa mandat pengguna akan digunakan untuk autentikasi layanan. Sertifikat server harus berisi nilai yang sama untuk properti SubjectName sebagai atribut findValue dalam <serviceCertificate>.

<system.serviceModel>
  <services>
    <service name="Microsoft.ServiceModel.Samples.CalculatorService"
             behaviorConfiguration="CalculatorServiceBehavior">
      <host>
        <baseAddresses>
          <!-- configure base address provided by host -->
          <add baseAddress ="http://localhost:8001/servicemodelsamples/service"/>
        </baseAddresses>
      </host>
      <!-- use base address provided by host, provide two endpoints -->
      <endpoint address="username"
                binding="wsHttpBinding"
                bindingConfiguration="Binding1"
                contract="Microsoft.ServiceModel.Samples.ICalculator" />
      <endpoint address="certificate"
                binding="wsHttpBinding"
                bindingConfiguration="Binding2"
                contract="Microsoft.ServiceModel.Samples.ICalculator" />
    </service>
  </services>

  <bindings>
    <wsHttpBinding>
      <!-- Username binding -->
      <binding name="Binding1">
        <security mode="Message">
    <message clientCredentialType="UserName" />
        </security>
      </binding>
      <!-- X509 certificate binding -->
      <binding name="Binding2">
        <security mode="Message">
          <message clientCredentialType="Certificate" />
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>

  <behaviors>
    <serviceBehaviors>
      <behavior name="CalculatorServiceBehavior" >
        <serviceDebug includeExceptionDetailInFaults ="true" />
        <serviceCredentials>
          <!--
          The serviceCredentials behavior allows one to specify a custom validator for username/password combinations.
          -->
          <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.MyCustomUserNameValidator, service" />
          <!--
          The serviceCredentials behavior allows one to specify authentication constraints on client certificates.
          -->
          <clientCertificate>
            <!--
            Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate
            is in the user's Trusted People store, then it will be trusted without performing a
            validation of the certificate's issuer chain. This setting is used here for convenience so that the
            sample can be run without having to have certificates issued by a certification authority (CA).
            This setting is less secure than the default, ChainTrust. The security implications of this
            setting should be carefully considered before using PeerOrChainTrust in production code.
            -->
            <authentication certificateValidationMode="PeerOrChainTrust" />
          </clientCertificate>
          <!--
          The serviceCredentials behavior allows one to define a service certificate.
          A service certificate is used by a client to authenticate the service and provide message protection.
          This configuration references the "localhost" certificate installed during the setup instructions.
          -->
          <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
        </serviceCredentials>
        <serviceAuthorization serviceAuthorizationManagerType="Microsoft.ServiceModel.Samples.MyServiceAuthorizationManager, service">
          <!--
          The serviceAuthorization behavior allows one to specify custom authorization policies.
          -->
          <authorizationPolicies>
            <add policyType="Microsoft.ServiceModel.Samples.CustomAuthorizationPolicy.MyAuthorizationPolicy, PolicyLibrary" />
          </authorizationPolicies>
        </serviceAuthorization>
      </behavior>
    </serviceBehaviors>
  </behaviors>

</system.serviceModel>

Setiap konfigurasi titik akhir klien terdiri dari nama konfigurasi, alamat absolut untuk titik akhir layanan, pengikatan, dan kontrak. Pengikatan klien dikonfigurasi dengan mode keamanan yang sesuai seperti yang dalam hal ini ditentukan dalam <keamanan> dan clientCredentialType seperti yang ditentukan dalam <pesan>.

<system.serviceModel>

    <client>
      <!-- Username based endpoint -->
      <endpoint name="Username"
            address="http://localhost:8001/servicemodelsamples/service/username"
    binding="wsHttpBinding"
    bindingConfiguration="Binding1"
                behaviorConfiguration="ClientCertificateBehavior"
                contract="Microsoft.ServiceModel.Samples.ICalculator" >
      </endpoint>
      <!-- X509 certificate based endpoint -->
      <endpoint name="Certificate"
                        address="http://localhost:8001/servicemodelsamples/service/certificate"
                binding="wsHttpBinding"
            bindingConfiguration="Binding2"
                behaviorConfiguration="ClientCertificateBehavior"
                contract="Microsoft.ServiceModel.Samples.ICalculator">
      </endpoint>
    </client>

    <bindings>
      <wsHttpBinding>
        <!-- Username binding -->
      <binding name="Binding1">
        <security mode="Message">
          <message clientCredentialType="UserName" />
        </security>
      </binding>
        <!-- X509 certificate binding -->
        <binding name="Binding2">
          <security mode="Message">
            <message clientCredentialType="Certificate" />
          </security>
        </binding>
    </wsHttpBinding>
    </bindings>

    <behaviors>
      <behavior name="ClientCertificateBehavior">
        <clientCredentials>
          <serviceCertificate>
            <!--
            Setting the certificateValidationMode to PeerOrChainTrust
            means that if the certificate
            is in the user's Trusted People store, then it will be
            trusted without performing a
            validation of the certificate's issuer chain. This setting
            is used here for convenience so that the
            sample can be run without having to have certificates
            issued by a certification authority (CA).
            This setting is less secure than the default, ChainTrust.
            The security implications of this
            setting should be carefully considered before using
            PeerOrChainTrust in production code.
            -->
            <authentication certificateValidationMode = "PeerOrChainTrust" />
          </serviceCertificate>
        </clientCredentials>
      </behavior>
    </behaviors>

  </system.serviceModel>

Untuk titik akhir berbasis nama pengguna, implementasi klien mengatur nama pengguna dan kata sandi yang akan digunakan.

// Create a client with Username endpoint configuration
CalculatorClient client1 = new CalculatorClient("Username");

client1.ClientCredentials.UserName.UserName = "test1";
client1.ClientCredentials.UserName.Password = "1tset";

try
{
    // Call the Add service operation.
    double value1 = 100.00D;
    double value2 = 15.99D;
    double result = client1.Add(value1, value2);
    Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
    ...
}
catch (Exception e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
}

client1.Close();

Untuk titik akhir berbasis sertifikat, implementasi klien menetapkan sertifikat klien yang akan digunakan.

// Create a client with Certificate endpoint configuration
CalculatorClient client2 = new CalculatorClient("Certificate");

client2.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "test1");

try
{
    // Call the Add service operation.
    double value1 = 100.00D;
    double value2 = 15.99D;
    double result = client2.Add(value1, value2);
    Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
    ...
}
catch (Exception e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
}

client2.Close();

Sampel ini menggunakan UserNamePasswordValidator kustom untuk memvalidasi nama pengguna dan kata sandi. Sampel mengimplementasikan MyCustomUserNamePasswordValidator, berasal dari UserNamePasswordValidator. Lihat dokumentasi tentang UserNamePasswordValidator untuk informasi selengkapnya. Untuk tujuan menunjukkan integrasi dengan UserNamePasswordValidator, sampel validator kustom ini mengimplementasikan metode Validateuntuk menerima pasangan nama pengguna/kata sandi di mana nama pengguna cocok dengan kata sandi seperti yang ditunjukkan dalam kode berikut.

public class MyCustomUserNamePasswordValidator : UserNamePasswordValidator
{
  // This method validates users. It allows in two users,
  // test1 and test2 with passwords 1tset and 2tset respectively.
  // This code is for illustration purposes only and
  // MUST NOT be used in a production environment because it
  // is NOT secure.
  public override void Validate(string userName, string password)
  {
    if (null == userName || null == password)
    {
      throw new ArgumentNullException();
    }

    if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
    {
      throw new SecurityTokenException("Unknown Username or Password");
    }
  }
}

Setelah validator diimplementasikan dalam kode layanan, host layanan harus diberi tahu tentang instans validator yang akan digunakan. Pemberitahuan ini dilakukan menggunakan kode berikut:

Servicehost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
serviceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new MyCustomUserNamePasswordValidatorProvider();

Atau Anda dapat melakukan hal yang sama dalam konfigurasi:

<behavior>
    <serviceCredentials>
      <!--
      The serviceCredentials behavior allows one to specify a custom validator for username/password combinations.
      -->
      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.MyCustomUserNameValidator, service" />
    ...
    </serviceCredentials>
</behavior>

Windows Communication Foundation (WCF) menyediakan model berbasis klaim yang kaya untuk melakukan pemeriksaan akses. Objek ServiceAuthorizationManager digunakan untuk melakukan pemeriksaan akses dan menentukan apakah klaim yang terkait dengan klien memenuhi persyaratan yang diperlukan untuk mengakses metode layanan.

Untuk tujuan demonstrasi, sampel ini menunjukkan implementasi ServiceAuthorizationManager yang mengimplementasikan metode CheckAccessCore untuk mengizinkan akses pengguna ke metode berdasarkan klaim jenis http://example.com/claims/allowedoperation yang nilainya adalah URI Tindakan dari operasi yang diizinkan untuk dipanggil.

public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
  protected override bool CheckAccessCore(OperationContext operationContext)
  {
    string action = operationContext.RequestContext.RequestMessage.Headers.Action;
    Console.WriteLine("action: {0}", action);
    foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
    {
      if ( cs.Issuer == ClaimSet.System )
      {
        foreach (Claim c in cs.FindClaims("http://example.com/claims/allowedoperation", Rights.PossessProperty))
        {
          Console.WriteLine("resource: {0}", c.Resource.ToString());
          if (action == c.Resource.ToString())
            return true;
        }
      }
    }
    return false;
  }
}

Setelah ServiceAuthorizationManager kustom diimplementasikan, host layanan harus diberi tahu tentang penggunaan ServiceAuthorizationManager. Pemberitahuan ini dilakukan seperti yang ditunjukkan dalam kode berikut.

<behavior>
    ...
    <serviceAuthorization serviceAuthorizationManagerType="Microsoft.ServiceModel.Samples.MyServiceAuthorizationManager, service">
        ...
    </serviceAuthorization>
</behavior>

Metode IAuthorizationPolicy utama untuk diimplementasikan adalah metode Evaluate(EvaluationContext, Object).

public class MyAuthorizationPolicy : IAuthorizationPolicy
{
    string id;

    public MyAuthorizationPolicy()
    {
    id =  Guid.NewGuid().ToString();
    }

    public bool Evaluate(EvaluationContext evaluationContext,
                                            ref object state)
    {
        bool bRet = false;
        CustomAuthState customstate = null;

        if (state == null)
        {
            customstate = new CustomAuthState();
            state = customstate;
        }
        else
            customstate = (CustomAuthState)state;
        Console.WriteLine("In Evaluate");
        if (!customstate.ClaimsAdded)
        {
           IList<Claim> claims = new List<Claim>();

           foreach (ClaimSet cs in evaluationContext.ClaimSets)
              foreach (Claim c in cs.FindClaims(ClaimTypes.Name,
                                         Rights.PossessProperty))
                  foreach (string s in
                        GetAllowedOpList(c.Resource.ToString()))
                  {
                       claims.Add(new
               Claim("http://example.com/claims/allowedoperation",
                                    s, Rights.PossessProperty));
                            Console.WriteLine("Claim added {0}", s);
                      }
                   evaluationContext.AddClaimSet(this,
                           new DefaultClaimSet(this.Issuer,claims));
                   customstate.ClaimsAdded = true;
                   bRet = true;
                }
         else
         {
              bRet = true;
         }
         return bRet;
     }
...
}

Kode sebelumnya menunjukkan bagaimana metode Evaluate(EvaluationContext, Object) memeriksa bahwa tidak ada klaim baru yang ditambahkan yang memengaruhi pemrosesan dan menambahkan klaim tertentu. Klaim yang diizinkan diperoleh dari metode GetAllowedOpList, yang diimplementasikan untuk mengembalikan daftar operasi tertentu yang diizinkan untuk dilakukan pengguna. Kebijakan otorisasi menambahkan klaim untuk mengakses operasi tertentu. Klaim ini kemudian digunakan oleh ServiceAuthorizationManager untuk melakukan keputusan pemeriksaan akses.

Setelah IAuthorizationPolicy kustom diterapkan, host layanan harus diberi tahu tentang kebijakan otorisasi yang akan digunakan.

<serviceAuthorization>
       <authorizationPolicies>
            <add policyType='Microsoft.ServiceModel.Samples.CustomAuthorizationPolicy.MyAuthorizationPolicy, PolicyLibrary' />
       </authorizationPolicies>
</serviceAuthorization>

Saat Anda menjalankan sampel, permintaan dan respons operasi ditampilkan di jendela konsol klien. Klien berhasil memanggil metode Tambahkan, Kurangi, dan Kalikan, dan mendapatkan pesan "Akses ditolak" saat mencoba memanggil metode Bagi. Tekan ENTER di jendela klien untuk mematikan komputer klien.

Menyiapkan File Batch

File batch Setup.bat yang disertakan dengan sampel ini memungkinkan Anda untuk mengonfigurasi server dengan sertifikat yang relevan untuk menjalankan aplikasi yang dihosting sendiri yang memerlukan keamanan berbasis sertifikat server.

Berikut ini memberikan gambaran singkat tentang berbagai bagian file batch sehingga dapat dimodifikasi untuk dijalankan dalam konfigurasi yang sesuai:

  • Membuat sertifikat server.

    Baris dari file batch Setup.bat berikut membuat sertifikat server yang akan digunakan. Variabel %SERVER_NAME% menentukan nama server. Ubah variabel ini untuk menentukan nama server Anda sendiri. Nilai defaultnya adalah localhost.

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    
  • Menginstal sertifikat server ke penyimpanan sertifikat tepercaya klien.

    Baris berikut dalam file batch Setup.bat menyalin sertifikat server ke penyimpanan orang tepercaya klien. Langkah ini diperlukan karena sertifikat yang dihasilkan oleh Makecert.exe tidak dipercaya secara implisit oleh sistem klien. Jika Anda sudah memiliki sertifikat yang berakar pada sertifikat akar tepercaya klien—misalnya, sertifikat yang dikeluarkan Microsoft—langkah mengisi penyimpanan sertifikat klien dengan sertifikat server tidak diperlukan.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    
  • Membuat sertifikat klien.

    Baris berikut dari file batch Setup.bat membuat sertifikat klien yang akan digunakan. Variabel %USER_NAME% menentukan nama server. Nilai ini diatur ke "test1" karena ini adalah nama yang dicari IAuthorizationPolicy. Jika Anda mengubah nilai %USER_NAME% Anda harus mengubah nilai terkait dalam metode IAuthorizationPolicy.Evaluate.

    Sertifikat disimpan di penyimpanan Saya (Pribadi) di lokasi penyimpanan CurrentUser.

    echo ************
    echo making client cert
    echo ************
    makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%CLIENT_NAME% -sky exchange -pe
    
  • Memasang sertifikat klien ke penyimpanan sertifikat tepercaya server.

    Baris berikut dalam file batch Setup.bat menyalin sertifikat klien ke penyimpanan orang tepercaya. Langkah ini diperlukan karena sertifikat yang dihasilkan oleh Makecert.exe tidak dipercaya secara implisit oleh sistem server. Jika Anda sudah memiliki sertifikat yang berakar dalam sertifikat akar tepercaya—misalnya, sertifikat yang dikeluarkan Microsoft—langkah mengisi penyimpanan sertifikat server dengan sertifikat klien ini tidak diperlukan.

    certmgr.exe -add -r CurrentUser -s My -c -n %CLIENT_NAME% -r LocalMachine -s TrustedPeople
    

Untuk menyiapkan dan membangun sampel

  1. Untuk membangun solusi, ikuti instruksi dalam Membangun Sampel Windows Communication Foundation.

  2. Untuk menjalankan sampel dalam konfigurasi tunggal atau lintas komputer, gunakan petunjuk berikut.

Catatan

Jika Anda menggunakan Svcutil.exe untuk meregenerasi konfigurasi untuk sampel ini, pastikan untuk mengubah nama titik akhir dalam konfigurasi klien agar sesuai dengan kode klien.

Untuk menjalankan sampel di komputer yang sama

  1. Buka Perintah Pengembang untuk Visual Studio dengan hak istimewa administrator dan jalankan Setup.bat dari folder penginstalan sampel. Ini memasang semua sertifikat yang diperlukan untuk menjalankan sampel.

    Catatan

    File batch Setup.bat dirancang untuk dijalankan dari Perintah Pengembang untuk Visual Studio. Variabel lingkungan PATH yang diatur dalam Perintah Pengembang untuk Visual Studio menunjuk ke direktori yang berisi hal yang perlu dieksekusi oleh skrip Setup.bat.

  2. Luncurkan Service.exe dari service\bin.

  3. Luncurkan Client.exe dari \client\bin. Aktivitas klien ditampilkan di aplikasi konsol klien.

Jika klien dan layanan tidak dapat berkomunikasi, lihat Tips Pemecahan Masalah untuk Sampel WCF.

Untuk menjalankan sampel di seluruh komputer

  1. Buat direktori di komputer layanan.

  2. Salin file program layanan dari \service\bin ke direktori pada komputer layanan. Salin juga file Setup.bat, Cleanup.bat, GetComputerName.vbs, dan ImportClientCert.bat ke komputer layanan.

  3. Buat direktori di komputer klien untuk binari klien.

  4. Salin file program klien ke direktori klien di komputer klien. Salin juga file Setup.bat, Cleanup.bat, dan ImportServiceCert.bat ke klien.

  5. Di server, jalankan setup.bat service di Perintah Pengembang untuk Visual Studio yang dibuka dengan hak istimewa administrator.

    Menjalankan setup.bat dengan argumen service akan membuat sertifikat layanan dengan nama domain komputer yang sepenuhnya memenuhi syarat dan mengekspor sertifikat layanan ke file bernamaService.cer.

  6. Edit Service.exe.config untuk mencerminkan nama sertifikat baru (dalam atribut findValue di <serviceCertificate>) FQDN komputer. Ubah juga nama komputer di <elemen service>/<baseAddresses> dari localhost menjadi nama komputer layanan Anda yang sepenuhnya memenuhi syarat.

  7. Salin file Service.cer dari direktori layanan ke direktori klien di komputer klien.

  8. Pada komputer klien, jalankan setup.bat client di Perintah Pengembang untuk Visual Studio yang dibuka dengan hak istimewa administrator.

    Menjalankan setup.bat dengan argumen client membuat sertifikat klien bernama test1 dan mengekspor sertifikat klien ke file bernama Client.cer.

  9. Di file Client.exe.config di komputer klien, ubah nilai alamat titik akhir agar sesuai dengan alamat baru layanan Anda. Lakukan ini dengan mengganti localhost dengan FQDN server.

  10. Salin file Client.cer dari direktori klien ke direktori layanan di server.

  11. Pada klien, jalankan ImportServiceCert.bat di Perintah Pengembang untuk Visual Studio yang dibuka dengan hak istimewa administrator.

    Langkah ini mengimpor sertifikat layanan dari file Service.cer ke penyimpanan CurrentUser - TrustedPeople.

  12. Di server, jalankan ImportClientCert.bat di Perintah Pengembang untuk Visual Studio yang dibuka dengan hak istimewa administrator.

    Langkah ini mengimpor sertifikat klien dari file Client.cer ke penyimpanan LocalMachine - TrustedPeople.

  13. Di komputer server, luncurkan Service.exe dari jendela perintah.

  14. Di komputer klien, luncurkan Client.exe dari jendela perintah.

    Jika klien dan layanan tidak dapat berkomunikasi, lihat Tips Pemecahan Masalah untuk Sampel WCF.

Melakukan pembersihan setelah sampel

Untuk melakukan pembersihan setelah sampel, jalankan Cleanup.bat di folder sampel setelah Anda selesai menjalankan sampel. Langkah ini menghapus sertifikat server dan klien dari penyimpanan sertifikat.

Catatan

Skrip ini tidak menghapus sertifikat layanan pada klien saat menjalankan sampel ini di seluruh komputer. Jika Anda telah menjalankan sampel WCF yang menggunakan sertifikat di seluruh komputer, pastikan untuk menghapus sertifikat layanan yang telah dipasang di penyimpanan CurrentUser - TrustedPeople. Untuk melakukannya, gunakan perintah berikut: certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name> Misalnya: certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.