Dela via


Betrodd fasadtjänst

Exemplet TrustedFacade visar hur du flödar uppringarens identitetsinformation från en tjänst till en annan med hjälp av säkerhetsinfrastrukturen i Windows Communication Foundation (WCF).

Det är ett vanligt designmönster att exponera funktionerna som tillhandahålls av en tjänst för det offentliga nätverket med hjälp av en fasadtjänst. Fasadtjänsten finns vanligtvis i perimeternätverket (även kallat DMZ, demilitariserad zon och skärmat undernät) och kommunicerar med en serverdelstjänst som implementerar affärslogiken och har åtkomst till interna data. Kommunikationskanalen mellan fasadtjänsten och serverdelstjänsten går genom en brandvägg och är vanligtvis begränsad endast för ett enda syfte.

Det här exemplet består av följande komponenter:

  • Kalkylatorklient

  • Kalkylatorfasadtjänst

  • Serverdelstjänst för kalkylator

Fasadtjänsten ansvarar för att verifiera begäran och autentisera uppringaren. Efter lyckad autentisering och validering vidarebefordras begäran till serverdelstjänsten med hjälp av den kontrollerade kommunikationskanalen från perimeternätverket till det interna nätverket. Som en del av den vidarebefordrade begäran innehåller fasadtjänsten information om anroparens identitet så att serverdelstjänsten kan använda den här informationen i sin bearbetning. Anroparens identitet överförs med hjälp av en Username säkerhetstoken i meddelanderubriken Security . Exemplet använder WCF-säkerhetsinfrastrukturen för att överföra och extrahera den här informationen från Security rubriken.

Viktigt!

Serverdelstjänsten litar på att fasadtjänsten autentiserar uppringaren. Därför autentiserar inte serverdelstjänsten anroparen igen. den använder identitetsinformationen som tillhandahålls av fasadtjänsten i den vidarebefordrade begäran. På grund av den här förtroenderelationen måste serverdelstjänsten autentisera fasadtjänsten för att säkerställa att det vidarebefordrade meddelandet kommer från en betrodd källa – i det här fallet fasadtjänsten.

Implementering

Det finns två kommunikationsvägar i det här exemplet. Det första är mellan klienten och fasadtjänsten, den andra är mellan fasadtjänsten och serverdelstjänsten.

Kommunikationsväg mellan klient- och fasadtjänsten

Klienten till fasadtjänstens kommunikationssökväg använder wsHttpBinding med en UserName klientautentiseringstyp. Det innebär att klienten använder användarnamn och lösenord för att autentisera till fasadtjänsten och fasadtjänsten använder X.509-certifikat för att autentisera till klienten. Bindningskonfigurationen ser ut som i följande exempel.

<bindings>
  <wsHttpBinding>
    <binding name="Binding1">
      <security mode="Message">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </wsHttpBinding>
</bindings>

Fasadtjänsten autentiserar anroparen med hjälp av anpassad UserNamePasswordValidator implementering. I demonstrationssyfte säkerställer autentiseringen endast att anroparens användarnamn matchar det presenterade lösenordet. I verkligheten autentiseras användaren förmodligen med Hjälp av Active Directory eller anpassad ASP.NET medlemskapsprovider. Valideringsimplementeringen finns i FacadeService.cs filen.

public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // check that username matches password
        if (null == userName || userName != password)
        {
            Console.WriteLine("Invalid username or password");
            throw new SecurityTokenValidationException(
                       "Invalid username or password");
        }
    }
}

Den anpassade validatorn är konfigurerad för att användas i serviceCredentials beteendet i konfigurationsfilen för fasadtjänsten. Det här beteendet används också för att konfigurera tjänstens X.509-certifikat.

<behaviors>
  <serviceBehaviors>
    <behavior name="FacadeServiceBehavior">
      <!--The serviceCredentials behavior allows you to define -->
      <!--a service certificate. -->
      <!--A service certificate is used by the service to  -->
      <!--authenticate itself to its clients and to provide  -->
      <!--message protection. -->
      <!--This configuration references the "localhost"  -->
      <!--certificate installed during the setup instructions. -->
      <serviceCredentials>
        <serviceCertificate
               findValue="localhost"
               storeLocation="LocalMachine"
               storeName="My"
               x509FindType="FindBySubjectName" />
        <userNameAuthentication userNamePasswordValidationMode="Custom"
            customUserNamePasswordValidatorType=
           "Microsoft.ServiceModel.Samples.MyUserNamePasswordValidator,
            FacadeService"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

Kommunikationsväg mellan Fasadtjänst och Serverdelstjänst

Fasadtjänsten till serverdelstjänstens kommunikationsväg använder en customBinding som består av flera bindningselement. Den här bindningen åstadkommer två saker. Den autentiserar fasadtjänsten och serverdelstjänsten för att säkerställa att kommunikationen är säker och kommer från en betrodd källa. Dessutom överför den även den första anroparens identitet i Username säkerhetstoken. I det här fallet överförs endast den första anroparens användarnamn till serverdelstjänsten, lösenordet ingår inte i meddelandet. Det beror på att serverdelstjänsten litar på att fasadtjänsten autentiserar anroparen innan begäran vidarebefordras till den. Eftersom fasadtjänsten autentiserar sig till serverdelstjänsten kan serverdelstjänsten lita på informationen i den vidarebefordrade begäran.

Följande är bindningskonfigurationen för den här kommunikationssökvägen.

<bindings>
  <customBinding>
    <binding name="ClientBinding">
      <security authenticationMode="UserNameOverTransport"/>
      <windowsStreamSecurity/>
      <tcpTransport/>
    </binding>
  </customBinding>
</bindings>

Säkerhetsbindningselementet ><tar hand om den första uppringarens användarnamnsöverföring och extrahering. WindowsStreamSecurity ><och< tcpTransport> tar hand om autentisering av fasad- och serverdelstjänster och meddelandeskydd.

För att vidarebefordra begäran måste fasadtjänstens implementering ange den första anroparens användarnamn så att WCF-säkerhetsinfrastrukturen kan placera detta i det vidarebefordrade meddelandet. Den första anroparens användarnamn anges i fasadtjänstens implementering genom att ange det i ClientCredentials egenskapen på den klientproxyinstans som fasadtjänsten använder för att kommunicera med serverdelstjänsten.

Följande kod visar hur GetCallerIdentity metoden implementeras på fasadtjänsten. Andra metoder använder samma mönster.

public string GetCallerIdentity()
{
    CalculatorClient client = new CalculatorClient();
    client.ClientCredentials.UserName.UserName = ServiceSecurityContext.Current.PrimaryIdentity.Name;
    string result = client.GetCallerIdentity();
    client.Close();
    return result;
}

Som du ser i föregående kod anges inte lösenordet för ClientCredentials egenskapen, utan endast användarnamnet anges. WCF-säkerhetsinfrastrukturen skapar en säkerhetstoken för användarnamn utan lösenord i det här fallet, vilket är exakt vad som krävs i det här scenariot.

På serverdelstjänsten måste informationen i användarnamnets säkerhetstoken autentiseras. Som standard försöker WCF-säkerheten mappa användaren till ett Windows-konto med det angivna lösenordet. I det här fallet finns det inget lösenord och serverdelstjänsten krävs inte för att autentisera användarnamnet eftersom autentiseringen redan utfördes av fasadtjänsten. För att implementera den här funktionen i WCF tillhandahålls en anpassad UserNamePasswordValidator som endast framtvingar att ett användarnamn anges i token och inte utför någon ytterligare autentisering.

public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // Ignore the password because it is empty,
        // we trust the facade service to authenticate the client.
        // Accept the username information here so that the
        // application gets access to it.
        if (null == userName)
        {
            Console.WriteLine("Invalid username");
            throw new
             SecurityTokenValidationException("Invalid username");
        }
    }
}

Den anpassade validatorn är konfigurerad för att användas i serviceCredentials beteendet i konfigurationsfilen för fasadtjänsten.

<behaviors>
  <serviceBehaviors>
    <behavior name="BackendServiceBehavior">
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom"
           customUserNamePasswordValidatorType=
          "Microsoft.ServiceModel.Samples.MyUserNamePasswordValidator,
           BackendService"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

För att extrahera användarnamnsinformation och information om det betrodda fasadtjänstkontot använder ServiceSecurityContext serverdelstjänstimplementeringen klassen. Följande kod visar hur GetCallerIdentity metoden implementeras.

public string GetCallerIdentity()
{
    // Facade service is authenticated using Windows authentication.
    //Its identity is accessible.
    // On ServiceSecurityContext.Current.WindowsIdentity.
    string facadeServiceIdentityName =
          ServiceSecurityContext.Current.WindowsIdentity.Name;

    // The client name is transmitted using Username authentication on
    //the message level without the password
    // using a supporting encrypted UserNameToken.
    // Claims extracted from this supporting token are available in
    // ServiceSecurityContext.Current.AuthorizationContext.ClaimSets
    // collection.
    string clientName = null;
    foreach (ClaimSet claimSet in
        ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
    {
        foreach (Claim claim in claimSet)
        {
            if (claim.ClaimType == ClaimTypes.Name &&
                                   claim.Right == Rights.Identity)
            {
                clientName = (string)claim.Resource;
                break;
            }
        }
    }
    if (clientName == null)
    {
        // In case there was no UserNameToken attached to the request.
        // In the real world implementation the service should reject
        // this request.
        return "Anonymous caller via " + facadeServiceIdentityName;
    }

    return clientName + " via " + facadeServiceIdentityName;
}

Informationen om fasadtjänstens konto extraheras med hjälp av egenskapen ServiceSecurityContext.Current.WindowsIdentity . För att komma åt informationen om den första anroparen använder ServiceSecurityContext.Current.AuthorizationContext.ClaimSets serverdelstjänsten egenskapen. Den söker efter ett Identity anspråk med en typ Name. Det här anspråket genereras automatiskt av WCF-säkerhetsinfrastrukturen från informationen i Username säkerhetstoken.

Köra exemplet

När du kör exemplet visas åtgärdsbegäranden och svar i klientkonsolfönstret. Tryck på RETUR i klientfönstret för att stänga av klienten. Du kan trycka på RETUR i fasaden och serverdelstjänstens konsolfönster för att stänga av tjänsterna.

Username authentication required.
Provide a valid machine or domain ac
   Enter username:
user
   Enter password:
****
user via MyMachine\testaccount
Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714

Press <ENTER> to terminate client.

Med Setup.bat batchfil som ingår i scenarioexemplet Betrodd fasad kan du konfigurera servern med ett relevant certifikat för att köra fasadtjänsten som kräver certifikatbaserad säkerhet för att autentisera sig mot klienten. Mer information finns i installationsproceduren i slutet av det här avsnittet.

Följande ger en kort översikt över de olika avsnitten i batchfilerna.

  • Skapa servercertifikatet.

    Följande rader från Setup.bat batchfil skapar det servercertifikat som ska användas.

    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
    

    Variabeln %SERVER_NAME% anger servernamnet – standardvärdet är localhost. Certifikatet lagras i LocalMachine-arkivet.

  • Installera fasadtjänstens certifikat i klientens betrodda certifikatarkiv.

    Följande rad kopierar fasadtjänstens certifikat till klientens betrodda personarkiv. Det här steget krävs eftersom certifikat som genereras av Makecert.exe inte är implicit betrodda av klientsystemet. Om du redan har ett certifikat som är rotat i ett klientbetrott rotcertifikat, till exempel ett Microsoft-utfärdat certifikat, krävs inte det här steget för att fylla i klientcertifikatarkivet med servercertifikatet.

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

Så här konfigurerar du, skapar och kör exemplet

  1. Kontrollera att du har utfört engångsinstallationsproceduren för Windows Communication Foundation-exempel.

  2. Om du vill skapa C# eller Visual Basic .NET-versionen av lösningen följer du anvisningarna i Skapa Windows Communication Foundation-exempel.

Så här kör du exemplet på samma dator

  1. Kontrollera att sökvägen innehåller mappen där Makecert.exe finns.

  2. Kör Setup.bat från exempelinstallationsmappen. Detta installerar alla certifikat som krävs för att köra exemplet.

  3. Starta BackendService.exe från katalogen \BackendService\bin i ett separat konsolfönster

  4. Starta FacadeService.exe från katalogen \FacadeService\bin i ett separat konsolfönster

  5. Starta Client.exe från \client\bin. Klientaktiviteten visas i klientkonsolprogrammet.

  6. Om klienten och tjänsten inte kan kommunicera kan du läsa Felsökningstips för WCF-exempel.

Rensa efter exemplet

  1. Kör Cleanup.bat i exempelmappen när du har kört exemplet.