Sdílet prostřednictvím


Zásada autorizace

Tato ukázka ukazuje, jak implementovat vlastní zásady autorizace deklarací identity a přidruženého vlastního správce autorizace služeb. To je užitečné, když služba provádí kontroly přístupu na základě deklarací identity k operacím služby a před kontrolou přístupu uděluje volajícímu určitá práva. Tato ukázka ukazuje proces přidávání deklarací identity i proces kontroly přístupu proti finalizované sadě deklarací identity. Všechny zprávy aplikace mezi klientem a serverem jsou podepsané a šifrované. Ve výchozím nastavení se k wsHttpBinding přihlášení k platnému účtu Systému Windows používá uživatelské jméno a heslo zadané klientem. Tato ukázka ukazuje, jak použít vlastní UserNamePasswordValidator k ověření klienta. Kromě toho tato ukázka ukazuje klienta, který se ověřuje ve službě pomocí certifikátu X.509. Tato ukázka ukazuje implementaci IAuthorizationPolicy a ServiceAuthorizationManager, která mezi nimi uděluje přístup ke konkrétním metodám služby pro konkrétní uživatele. Tato ukázka je založená na uživatelském jménu zabezpečení zpráv, ale ukazuje, jak provést transformaci deklarace identity před ServiceAuthorizationManager zavolání.

Poznámka:

Postup nastavení a pokyny k sestavení pro tuto ukázku najdete na konci tohoto tématu.

V souhrnu tato ukázka ukazuje, jak:

  • Klient se dá ověřit pomocí uživatelského jména a hesla.

  • Klient se dá ověřit pomocí certifikátu X.509.

  • Server ověří přihlašovací údaje klienta vůči vlastnímu UsernamePassword validátoru.

  • Server se ověřuje pomocí certifikátu X.509 serveru.

  • Server může použít ServiceAuthorizationManager k řízení přístupu k určitým metodám ve službě.

  • Jak implementovat IAuthorizationPolicy.

Služba zveřejňuje dva koncové body pro komunikaci se službou definovanou pomocí konfiguračního souboru App.config. Každý koncový bod se skládá z adresy, vazby a kontraktu. Jedna vazba je nakonfigurovaná se standardní wsHttpBinding vazbou, která používá ověřování uživatelských jmen WS-Security a klienta. Druhá vazba je nakonfigurována se standardní wsHttpBinding vazbou, která používá ověřování pomocí WS-Security a klientského certifikátu. > Chování <určuje, že se přihlašovací údaje uživatele použijí k ověřování služby. Certifikát serveru musí obsahovat stejnou hodnotu vlastnosti SubjectName jako atribut v< serviceCertificate>.findValue

<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>

Každá konfigurace koncového bodu klienta se skládá z názvu konfigurace, absolutní adresy koncového bodu služby, vazby a kontraktu. Vazba klienta je nakonfigurována s odpovídajícím režimem zabezpečení, jak je uvedeno v tomto případě v <zabezpečení> a clientCredentialType jak je uvedeno ve< zprávě.>

<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>

Pro koncový bod založený na uživatelském jménu nastaví implementace klienta uživatelské jméno a heslo, které se má použít.

// 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();

U koncového bodu založeného na certifikátu nastaví implementace klienta klientský certifikát, který se má použít.

// 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();

Tato ukázka používá vlastní UserNamePasswordValidator k ověření uživatelských jmen a hesel. Ukázka implementuje MyCustomUserNamePasswordValidator, odvozeno z UserNamePasswordValidator. Další informace najdete v dokumentaci UserNamePasswordValidator . Pro účely předvedení integrace s UserNamePasswordValidatortouto vlastní ukázkou validátoru Validate implementuje metodu pro příjem dvojic uživatelského jména a hesla, kde uživatelské jméno odpovídá heslu, jak je znázorněno v následujícím kódu.

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");
    }
  }
}

Po implementaci validátoru v kódu služby musí být hostitel služby informován o instanci validátoru, která se má použít. To se provádí pomocí následujícího kódu:

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

Nebo můžete provést totéž v konfiguraci:

<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) poskytuje bohatý model založený na deklarací identity pro provádění kontrol přístupu. Objekt ServiceAuthorizationManager slouží k provedení kontroly přístupu a určení, zda deklarace identity přidružené k klientovi splňují požadavky potřebné pro přístup k metodě služby.

Pro účely demonstrace tato ukázka ukazuje implementaci ServiceAuthorizationManager , která implementuje metodu CheckAccessCore , která uživateli umožňuje přístup k metodám na základě deklarací typu http://example.com/claims/allowedoperation , jejichž hodnota je identifikátor URI akce operace, která má být volána.

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;
  }
}

Jakmile je vlastní ServiceAuthorizationManager implementovaný, musí být hostitel služby informován o tom, co ServiceAuthorizationManager se má použít. To se provádí, jak je znázorněno v následujícím kódu.

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

IAuthorizationPolicy Primární metodouEvaluate(EvaluationContext, Object), která se má implementovat, je metoda.

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;
     }
...
}

Předchozí kód ukazuje, jak Evaluate(EvaluationContext, Object) metoda kontroluje, že nebyly přidány žádné nové deklarace identity, které ovlivňují zpracování a přidávají konkrétní deklarace identity. Deklarace identity, které jsou povoleny, jsou získány z GetAllowedOpList metody, která je implementována k vrácení konkrétního seznamu operací, které uživatel může provést. Zásady autorizace přidávají deklarace identity pro přístup ke konkrétní operaci. Později ho ServiceAuthorizationManager použije k provádění rozhodnutí o kontrole přístupu.

Jakmile je vlastní IAuthorizationPolicy implementovaný, musí být hostitel služby informován o autorizačních zásadách, které se mají použít.

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

Při spuštění ukázky se požadavky na operace a odpovědi zobrazí v okně konzoly klienta. Klient úspěšně volá metodu Add, Subtract a Multiple a při pokusu o volání metody Divide získá zprávu "Přístup je odepřen". Stisknutím klávesy ENTER v okně klienta klienta ukončete klienta.

Nastavení dávkového souboru

Dávkový soubor Setup.bat, který je součástí této ukázky, umožňuje nakonfigurovat server s relevantními certifikáty pro spuštění aplikace v místním prostředí, která vyžaduje zabezpečení založené na certifikátech serveru.

Níže najdete stručný přehled různých částí dávkových souborů, aby je bylo možné upravit tak, aby běžely v příslušné konfiguraci:

  • Vytvoření certifikátu serveru

    Následující řádky z dávkového souboru Setup.bat vytvoří certifikát serveru, který se má použít. Proměnná %SERVER_NAME% určuje název serveru. Změňte tuto proměnnou tak, aby byla zadána vlastní název serveru. Výchozí hodnota je 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
    
  • Instalace certifikátu serveru do důvěryhodného úložiště certifikátů klienta

    Následující řádky v dávkovém souboru Setup.bat zkopírují certifikát serveru do úložiště důvěryhodných osob klienta. Tento krok je povinný, protože certifikáty vygenerované Makecert.exe nejsou implicitně důvěryhodné klientským systémem. Pokud už máte certifikát, který je kořenový v kořenovém certifikátu klienta ( například certifikát vydaný Microsoftem), tento krok naplnění úložiště klientských certifikátů certifikátem pomocí certifikátu serveru se nevyžaduje.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    
  • Vytvoření klientského certifikátu

    Následující řádky z dávkového souboru Setup.bat vytvoří klientský certifikát, který se má použít. Proměnná %USER_NAME% určuje název serveru. Tato hodnota je nastavená na test1, protože se jedná o název, který IAuthorizationPolicy hledá. Pokud změníte hodnotu %USER_NAME%, musíte změnit odpovídající hodnotu v IAuthorizationPolicy.Evaluate metodě.

    Certifikát je uložený v úložišti My (Personal) v umístění Úložiště CurrentUser.

    echo ************
    echo making client cert
    echo ************
    makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%CLIENT_NAME% -sky exchange -pe
    
  • Instalace klientského certifikátu do důvěryhodného úložiště certifikátů serveru

    Následující řádky v dávkovém souboru Setup.bat zkopírují klientský certifikát do úložiště důvěryhodných osob. Tento krok je povinný, protože certifikáty generované Makecert.exe nejsou implicitně důvěryhodné systémem serveru. Pokud už máte certifikát, který je kořenový v důvěryhodném kořenovém certifikátu , například certifikát vydaný Microsoftem, tento krok naplnění úložiště certifikátů serveru klientským certifikátem se nevyžaduje.

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

Nastavení a sestavení ukázky

  1. Pokud chcete sestavit řešení, postupujte podle pokynů v části Sestavení ukázek Windows Communication Foundation.

  2. Pokud chcete spustit ukázku v konfiguraci jednoho nebo více počítačů, postupujte podle následujících pokynů.

Poznámka:

Pokud použijete Svcutil.exe k opětovnému vygenerování konfigurace pro tuto ukázku, nezapomeňte upravit název koncového bodu v konfiguraci klienta tak, aby odpovídal kódu klienta.

Spuštění ukázky na stejném počítači

  1. Otevřete příkazový řádek pro vývojáře pro Visual Studio s oprávněními správce a spusťte Setup.bat z ukázkové instalační složky. Tím se nainstalují všechny certifikáty potřebné pro spuštění ukázky.

    Poznámka:

    Dávkový soubor Setup.bat je navržený tak, aby běžel z příkazového řádku pro vývojáře pro Visual Studio. Proměnná prostředí PATH nastavená v příkazovém řádku pro vývojáře pro Visual Studio odkazuje na adresář, který obsahuje spustitelné soubory vyžadované skriptem Setup.bat .

  2. Spusťte Service.exe ze služby\bin.

  3. Spusťte Client.exe ze souboru \client\bin. Aktivita klienta se zobrazí v aplikaci konzoly klienta.

Pokud klient a služba nemůžou komunikovat, přečtěte si téma Řešení potíží Tipy pro ukázky WCF.

Spuštění ukázky napříč počítači

  1. Vytvořte adresář na počítači služby.

  2. Zkopírujte soubory programu služby ze složky \service\bin do adresáře v počítači služby. Zkopírujte také soubory Setup.bat, Cleanup.bat, GetComputerName.vbs a ImportClientCert.bat do počítače služby.

  3. Vytvořte adresář v klientském počítači pro binární soubory klienta.

  4. Zkopírujte soubory klientského programu do klientského adresáře v klientském počítači. Zkopírujte také soubory Setup.bat, Cleanup.bat a ImportServiceCert.bat do klienta.

  5. Na serveru spusťte setup.bat service příkazový řádek pro vývojáře pro Visual Studio otevřený s oprávněními správce.

    Spuštění setup.bat s argumentem service vytvoří certifikát služby s plně kvalifikovaným názvem domény počítače a exportuje certifikát služby do souboru s názvem Service.cer.

  6. Upravte Service.exe.config tak, aby odrážel nový název certifikátu (v findValue atributu <v serviceCertificate>), který je stejný jako plně kvalifikovaný název domény počítače. Změňte také název počítače v elementu <service>/<baseAddresses> z localhost na plně kvalifikovaný název vašeho počítače služby.

  7. Zkopírujte soubor Service.cer z adresáře služby do klientského adresáře v klientském počítači.

  8. Na klientovi spusťte setup.bat client příkazový řádek pro vývojáře pro Visual Studio otevřený s oprávněními správce.

    Spuštění setup.bat s argumentem client vytvoří klientský certifikát s názvem test1 a exportuje klientský certifikát do souboru s názvem Client.cer.

  9. V souboru Client.exe.config na klientském počítači změňte hodnotu adresy koncového bodu tak, aby odpovídala nové adrese vaší služby. Uděláte to tak , že nahradíte localhost plně kvalifikovaným názvem domény serveru.

  10. Zkopírujte soubor Client.cer z klientského adresáře do adresáře služby na serveru.

  11. Na klientovi spusťte ImportServiceCert.bat v příkazovém řádku pro vývojáře pro Visual Studio otevřené s oprávněními správce.

    Tím se certifikát služby naimportuje ze souboru Service.cer do úložiště CurrentUser – Trusted Lidé.

  12. Na serveru spusťte ImportClientCert.bat v příkazovém řádku pro vývojáře pro Visual Studio otevřené s oprávněními správce.

    Tím se klientský certifikát naimportuje ze souboru Client.cer do úložiště LocalMachine – Důvěryhodné Lidé.

  13. Na serverovém počítači spusťte Service.exe z okna příkazového řádku.

  14. Na klientském počítači spusťte Client.exe z okna příkazového řádku.

    Pokud klient a služba nemůžou komunikovat, přečtěte si téma Řešení potíží Tipy pro ukázky WCF.

Vyčištění po ukázce

Pokud chcete ukázku vyčistit, spusťte po dokončení spuštění ukázky Cleanup.bat ve složce s ukázkami. Tím se odeberou certifikáty serveru a klienta z úložiště certifikátů.

Poznámka:

Tento skript při spuštění této ukázky na počítačích neodebere certifikáty služby v klientovi. Pokud jste spustili ukázky WCF, které používají certifikáty napříč počítači, nezapomeňte vymazat certifikáty služeb nainstalované v úložišti CurrentUser – Důvěryhodné Lidé. K tomu použijte následující příkaz: certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name> Například: certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.