Vlastní token

Tato ukázka ukazuje, jak do aplikace WCF (Windows Communication Foundation) přidat vlastní implementaci tokenu. Příklad používá k bezpečnému CreditCardToken předávání informací o klientských platebních kartách službě. Token se předává v hlavičce zprávy WS-Security a je podepsaný a šifrovaný pomocí elementu symetrické vazby zabezpečení spolu s textem zprávy a dalšími hlavičkami zprávy. To je užitečné v případech, kdy předdefinované tokeny nestačí. Tato ukázka ukazuje, jak službě poskytnout vlastní token zabezpečení místo použití jednoho z předdefinovaných tokenů. Služba implementuje kontrakt, který definuje komunikační vzor žádosti a odpovědi.

Poznámka:

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

Tento příklad ukazuje následující souhrn:

  • Jak může klient předat vlastní token zabezpečení službě.

  • Jak může služba využívat a ověřit vlastní token zabezpečení.

  • Jak kód služby WCF může získat informace o přijatých tokenech zabezpečení, včetně vlastního tokenu zabezpečení.

  • Jak se certifikát X.509 serveru používá k ochraně symetrického klíče používaného k šifrování zpráv a podpisu.

Ověřování klientů pomocí vlastního tokenu zabezpečení

Služba zveřejňuje jeden koncový bod, který se vytváří prostřednictvím kódu programu pomocí BindingHelper a EchoServiceHost tříd. Koncový bod se skládá z adresy, vazby a kontraktu. Vazba je nakonfigurována s vlastní vazbou pomocí SymmetricSecurityBindingElement a HttpTransportBindingElement. Tato ukázka nastaví SymmetricSecurityBindingElement použití certifikátu X.509 služby k ochraně symetrického klíče během přenosu a předání vlastní CreditCardToken hlavičky zprávy WS-Security jako podepsaného a šifrovaného tokenu zabezpečení. Chování určuje přihlašovací údaje služby, které se mají použít pro ověřování klientů, a také informace o certifikátu X.509 služby.

public static class BindingHelper
{
    public static Binding CreateCreditCardBinding()
    {
        var httpTransport = new HttpTransportBindingElement();

        // The message security binding element will be configured to require a credit card.
        // The token that is encrypted with the service's certificate.
        var messageSecurity = new SymmetricSecurityBindingElement();
        messageSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CreditCardTokenParameters());
        X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters();
        x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.Never;
        messageSecurity.ProtectionTokenParameters = x509ProtectionParameters;
        return new CustomBinding(messageSecurity, httpTransport);
    }
}

K využití tokenu platební karty ve zprávě použije ukázka k poskytnutí této funkce vlastní přihlašovací údaje služby. Třída přihlašovacích údajů služby se nachází ve CreditCardServiceCredentials třídě a je přidána do kolekcí chování hostitele služby v EchoServiceHost.InitializeRuntime metodě.

class EchoServiceHost : ServiceHost
{
    string creditCardFile;

    public EchoServiceHost(parameters Uri[] addresses)
        : base(typeof(EchoService), addresses)
    {
        creditCardFile = ConfigurationManager.AppSettings["creditCardFile"];
        if (string.IsNullOrEmpty(creditCardFile))
        {
            throw new ConfigurationErrorsException("creditCardFile not specified in service config");
        }

        creditCardFile = String.Format("{0}\\{1}", System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, creditCardFile);
    }

    override protected void InitializeRuntime()
    {
        // Create a credit card service credentials and add it to the behaviors.
        CreditCardServiceCredentials serviceCredentials = new CreditCardServiceCredentials(this.creditCardFile);
        serviceCredentials.ServiceCertificate.SetCertificate("CN=localhost", StoreLocation.LocalMachine, StoreName.My);
        this.Description.Behaviors.Remove((typeof(ServiceCredentials)));
        this.Description.Behaviors.Add(serviceCredentials);

        // Register a credit card binding for the endpoint.
        Binding creditCardBinding = BindingHelper.CreateCreditCardBinding();
        this.AddServiceEndpoint(typeof(IEchoService), creditCardBinding, string.Empty);

        base.InitializeRuntime();
    }
}

Koncový bod klienta se konfiguruje podobným způsobem jako koncový bod služby. Klient používá stejnou BindingHelper třídu k vytvoření vazby. Zbytek nastavení se nachází ve Client třídě. Klient také nastaví informace, které mají být obsaženy v CreditCardToken certifikátu služby X.509 v instalačním kódu, přidáním CreditCardClientCredentials instance se správnými daty do kolekce chování koncových bodů klienta. Ukázka používá certifikát X.509 s názvem subjektu nastaveným jako CN=localhost certifikát služby.

Binding creditCardBinding = BindingHelper.CreateCreditCardBinding();
var serviceAddress = new EndpointAddress("http://localhost/servicemodelsamples/service.svc");

// Create a client with given client endpoint configuration.
channelFactory = new ChannelFactory<IEchoService>(creditCardBinding, serviceAddress);

// Configure the credit card credentials on the channel factory.
var credentials =
      new CreditCardClientCredentials(
      new CreditCardInfo(creditCardNumber, issuer, expirationTime));
// Configure the service certificate on the credentials.
credentials.ServiceCertificate.SetDefaultCertificate(
      "CN=localhost", StoreLocation.LocalMachine, StoreName.My);

// Replace ClientCredentials with CreditCardClientCredentials.
channelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
channelFactory.Endpoint.Behaviors.Add(credentials);

client = channelFactory.CreateChannel();

Console.WriteLine($"Echo service returned: {client.Echo()}");

((IChannel)client).Close();
channelFactory.Close();

Implementace vlastního tokenu zabezpečení

Pokud chcete ve WCF povolit vlastní token zabezpečení, vytvořte reprezentaci objektu vlastního tokenu zabezpečení. Ukázka má tuto reprezentaci CreditCardToken ve třídě. Reprezentace objektu zodpovídá za uchovávání všech relevantních informací o tokenech zabezpečení a za poskytnutí seznamu klíčů zabezpečení obsažených v tokenu zabezpečení. V tomto případě token zabezpečení platební karty neobsahuje žádný bezpečnostní klíč.

Další část popisuje, co je potřeba udělat, aby se vlastní token přenášel přes drát a spotřeboval koncový bod WCF.

class CreditCardToken : SecurityToken
{
    CreditCardInfo cardInfo;
    DateTime effectiveTime = DateTime.UtcNow;
    string id;
    ReadOnlyCollection<SecurityKey> securityKeys;

    public CreditCardToken(CreditCardInfo cardInfo) : this(cardInfo, Guid.NewGuid().ToString()) { }

    public CreditCardToken(CreditCardInfo cardInfo, string id)
    {
        if (cardInfo == null)
            throw new ArgumentNullException(nameof(cardInfo));

        if (id == null)
            throw new ArgumentNullException(nameof(id));

        this.cardInfo = cardInfo;
        this.id = id;

        // The credit card token is not capable of any cryptography.
        this.securityKeys = new ReadOnlyCollection<SecurityKey>(new List<SecurityKey>());
    }

    public CreditCardInfo CardInfo { get { return this.cardInfo; } }

    public override ReadOnlyCollection<SecurityKey> SecurityKeys { get { return this.securityKeys; } }

    public override DateTime ValidFrom { get { return this.effectiveTime; } }
    public override DateTime ValidTo { get { return this.cardInfo.ExpirationDate; } }
    public override string Id { get { return this.id; } }
}

Získání tokenu vlastní platební karty do zprávy a ze zprávy

Serializátory tokenů zabezpečení ve WCF jsou zodpovědné za vytvoření objektové reprezentace tokenů zabezpečení z XML ve zprávě a vytvoření XML formuláře tokenů zabezpečení. Zodpovídají také za další funkce, jako je čtení a zápis identifikátorů klíčů odkazující na tokeny zabezpečení, ale v tomto příkladu se používají jenom funkce související s tokeny zabezpečení. Pokud chcete povolit vlastní token, musíte implementovat vlastní serializátor tokenu zabezpečení. Tato ukázka používá třídu CreditCardSecurityTokenSerializer pro tento účel.

Ve službě vlastní serializátor načte formulář XML vlastního tokenu a vytvoří z něj reprezentaci objektu vlastního tokenu.

V klientovi CreditCardSecurityTokenSerializer třída zapisuje informace obsažené v reprezentaci objektu tokenu zabezpečení do zapisovače XML.

public class CreditCardSecurityTokenSerializer : WSSecurityTokenSerializer
{
    public CreditCardSecurityTokenSerializer(SecurityTokenVersion version) : base() { }

    protected override bool CanReadTokenCore(XmlReader reader)
    {
        XmlDictionaryReader localReader = XmlDictionaryReader.CreateDictionaryReader(reader);

        if (reader == null)
            throw new ArgumentNullException(nameof(reader));

        if (reader.IsStartElement(Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace))
            return true;

        return base.CanReadTokenCore(reader);
    }

    protected override SecurityToken ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)
    {
        if (reader == null)
            throw new ArgumentNullException(nameof(reader));

        if (reader.IsStartElement(Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace))
        {
            string id = reader.GetAttribute(Constants.Id, Constants.WsUtilityNamespace);

            reader.ReadStartElement();

            // Read the credit card number.
            string creditCardNumber = reader.ReadElementString(Constants.CreditCardNumberElementName, Constants.CreditCardTokenNamespace);

            // Read the expiration date.
            string expirationTimeString = reader.ReadElementString(Constants.CreditCardExpirationElementName, Constants.CreditCardTokenNamespace);
            DateTime expirationTime = XmlConvert.ToDateTime(expirationTimeString, XmlDateTimeSerializationMode.Utc);

            // Read the issuer of the credit card.
            string creditCardIssuer = reader.ReadElementString(Constants.CreditCardIssuerElementName, Constants.CreditCardTokenNamespace);
            reader.ReadEndElement();

            var cardInfo = new CreditCardInfo(creditCardNumber, creditCardIssuer, expirationTime);

            return new CreditCardToken(cardInfo, id);
        }
        else
        {
            return WSSecurityTokenSerializer.DefaultInstance.ReadToken(reader, tokenResolver);
        }
    }

    protected override bool CanWriteTokenCore(SecurityToken token)
    {
        if (token is CreditCardToken)
            return true;
        return base.CanWriteTokenCore(token);
    }

    protected override void WriteTokenCore(XmlWriter writer, SecurityToken token)
    {
        if (writer == null)
            throw new ArgumentNullException(nameof(writer));
        if (token == null)
            throw new ArgumentNullException(nameof(token));

        CreditCardToken c = token as CreditCardToken;
        if (c != null)
        {
            writer.WriteStartElement(Constants.CreditCardTokenPrefix, Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace);
            writer.WriteAttributeString(Constants.WsUtilityPrefix, Constants.Id, Constants.WsUtilityNamespace, token.Id);
            writer.WriteElementString(Constants.CreditCardNumberElementName, Constants.CreditCardTokenNamespace, c.CardInfo.CardNumber);
            writer.WriteElementString(Constants.CreditCardExpirationElementName, Constants.CreditCardTokenNamespace, XmlConvert.ToString(c.CardInfo.ExpirationDate, XmlDateTimeSerializationMode.Utc));
            writer.WriteElementString(Constants.CreditCardIssuerElementName, Constants.CreditCardTokenNamespace, c.CardInfo.CardIssuer);
            writer.WriteEndElement();
            writer.Flush();
        }
        else
        {
            base.WriteTokenCore(writer, token);
        }
    }
}

Vytvoření třídy zprostředkovatele tokenu a ověřovacího tokenu

Přihlašovací údaje klienta a služby zodpovídají za poskytování instance správce tokenů zabezpečení. Instance správce tokenů zabezpečení slouží k získání zprostředkovatelů tokenů, ověřovacích objektů tokenů a serializátorů tokenů.

Zprostředkovatel tokenu vytvoří reprezentaci objektu tokenu na základě informací obsažených v přihlašovacích údajích klienta nebo služby. Reprezentace objektu tokenu se pak zapíše do zprávy pomocí serializátoru tokenu (popsáno v předchozí části).

Ověřovací program tokenu ověří tokeny, které dorazí do zprávy. Reprezentace objektu příchozího tokenu je vytvořena serializátorem tokenu. Toto vyjádření objektu se pak předá ověřovacímu objektu ověřovacímu objektu tokenu. Po úspěšném ověření tokenu vrátí ověřovací program tokenu IAuthorizationPolicy kolekci objektů, které představují informace obsažené v tokenu. Tyto informace se později použijí během zpracování zpráv k provádění rozhodnutí o autorizaci a k poskytování deklarací identity pro aplikaci. V tomto příkladu se pro tento účel používá CreditCardTokenAuthorizationPolicy ověřovací token platební karty.

Serializátor tokenu zodpovídá za získání reprezentace objektu tokenu do a z drátu. To je popsáno v předchozí části.

V této ukázce používáme zprostředkovatele tokenu pouze u klienta a ověřovacího objektu tokenu pouze ve službě, protože chceme předávat token platební karty pouze ve směru klient-služba.

Funkce v klientovi se nachází v objektech CreditCardClientCredentialsa CreditCardClientCredentialsSecurityTokenManagerCreditCardTokenProvider třídách.

Ve službě se funkce nachází v objektu CreditCardServiceCredentials, CreditCardServiceCredentialsSecurityTokenManagerCreditCardTokenAuthenticator a CreditCardTokenAuthorizationPolicy třídy.

    public class CreditCardClientCredentials : ClientCredentials
    {
        CreditCardInfo creditCardInfo;

        public CreditCardClientCredentials(CreditCardInfo creditCardInfo)
            : base()
        {
            if (creditCardInfo == null)
                throw new ArgumentNullException(nameof(creditCardInfo));

            this.creditCardInfo = creditCardInfo;
        }

        public CreditCardInfo CreditCardInfo
        {
            get { return this.creditCardInfo; }
        }

        protected override ClientCredentials CloneCore()
        {
            return new CreditCardClientCredentials(this.creditCardInfo);
        }

        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new CreditCardClientCredentialsSecurityTokenManager(this);
        }
    }

    public class CreditCardClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager
    {
        CreditCardClientCredentials creditCardClientCredentials;

        public CreditCardClientCredentialsSecurityTokenManager(CreditCardClientCredentials creditCardClientCredentials)
            : base (creditCardClientCredentials)
        {
            this.creditCardClientCredentials = creditCardClientCredentials;
        }

        public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
        {
            // Handle this token for Custom.
            if (tokenRequirement.TokenType == Constants.CreditCardTokenType)
                return new CreditCardTokenProvider(this.creditCardClientCredentials.CreditCardInfo);
            // Return server cert.
            else if (tokenRequirement is InitiatorServiceModelSecurityTokenRequirement)
            {
                if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
                {
                    return new X509SecurityTokenProvider(creditCardClientCredentials.ServiceCertificate.DefaultCertificate);
                }
            }

            return base.CreateSecurityTokenProvider(tokenRequirement);
        }

        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
        {

            return new CreditCardSecurityTokenSerializer(version);
        }

    }

    class CreditCardTokenProvider : SecurityTokenProvider
    {
        CreditCardInfo creditCardInfo;

        public CreditCardTokenProvider(CreditCardInfo creditCardInfo) : base()
        {
            if (creditCardInfo == null)
                throw new ArgumentNullException(nameof(creditCardInfo));

            this.creditCardInfo = creditCardInfo;
        }

        protected override SecurityToken GetTokenCore(TimeSpan timeout)
        {
            SecurityToken result = new CreditCardToken(this.creditCardInfo);
            return result;
        }
    }

    public class CreditCardServiceCredentials : ServiceCredentials
    {
        string creditCardFile;

        public CreditCardServiceCredentials(string creditCardFile)
            : base()
        {
            if (creditCardFile == null)
                throw new ArgumentNullException(nameof(creditCardFile));

            this.creditCardFile = creditCardFile;
        }

        public string CreditCardDataFile
        {
            get { return this.creditCardFile; }
        }

        protected override ServiceCredentials CloneCore()
        {
            return new CreditCardServiceCredentials(this.creditCardFile);
        }

        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new CreditCardServiceCredentialsSecurityTokenManager(this);
        }
    }

    public class CreditCardServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager
    {
        CreditCardServiceCredentials creditCardServiceCredentials;

        public CreditCardServiceCredentialsSecurityTokenManager(CreditCardServiceCredentials creditCardServiceCredentials)
            : base(creditCardServiceCredentials)
        {
            this.creditCardServiceCredentials = creditCardServiceCredentials;
        }

        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            if (tokenRequirement.TokenType == Constants.CreditCardTokenType)
            {
                outOfBandTokenResolver = null;
                return new CreditCardTokenAuthenticator(creditCardServiceCredentials.CreditCardDataFile);
            }

            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
        }

        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
        {
            return new CreditCardSecurityTokenSerializer(version);
        }
    }

    class CreditCardTokenAuthenticator : SecurityTokenAuthenticator
    {
        string creditCardsFile;
        public CreditCardTokenAuthenticator(string creditCardsFile)
        {
            this.creditCardsFile = creditCardsFile;
        }

        protected override bool CanValidateTokenCore(SecurityToken token)
        {
            return (token is CreditCardToken);
        }

        protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token)
        {
            CreditCardToken creditCardToken = token as CreditCardToken;

            if (creditCardToken.CardInfo.ExpirationDate < DateTime.UtcNow)
                throw new SecurityTokenValidationException("The credit card has expired.");
            if (!IsCardNumberAndExpirationValid(creditCardToken.CardInfo))
                throw new SecurityTokenValidationException("Unknown or invalid credit card.");

            // the credit card token has only 1 claim - the card number. The issuer for the claim is the
            // credit card issuer

            var cardIssuerClaimSet = new DefaultClaimSet(new Claim(ClaimTypes.Name, creditCardToken.CardInfo.CardIssuer, Rights.PossessProperty));
            var cardClaimSet = new DefaultClaimSet(cardIssuerClaimSet, new Claim(Constants.CreditCardNumberClaim, creditCardToken.CardInfo.CardNumber, Rights.PossessProperty));
            var policies = new List<IAuthorizationPolicy>(1);
            policies.Add(new CreditCardTokenAuthorizationPolicy(cardClaimSet));
            return policies.AsReadOnly();
        }

        /// <summary>
        /// Helper method to check if a given credit card entry is present in the User DB
        /// </summary>
        private bool IsCardNumberAndExpirationValid(CreditCardInfo cardInfo)
        {
            try
            {
                using (var myStreamReader = new StreamReader(this.creditCardsFile))
                {
                    string line = "";
                    while ((line = myStreamReader.ReadLine()) != null)
                    {
                        string[] splitEntry = line.Split('#');
                        if (splitEntry[0] == cardInfo.CardNumber)
                        {
                            string expirationDateString = splitEntry[1].Trim();
                            DateTime expirationDateOnFile = DateTime.Parse(expirationDateString, System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.AdjustToUniversal);
                            if (cardInfo.ExpirationDate == expirationDateOnFile)
                            {
                                string issuer = splitEntry[2];
                                return issuer.Equals(cardInfo.CardIssuer, StringComparison.InvariantCultureIgnoreCase);
                            }
                            else
                            {
                                return false;
                            }
                        }
                    }
                    return false;
                }
            }
            catch (Exception e)
            {
                throw new Exception("BookStoreService: Error while retrieving credit card information from User DB " + e.ToString());
            }
        }
    }

    public class CreditCardTokenAuthorizationPolicy : IAuthorizationPolicy
    {
        string id;
        ClaimSet issuer;
        IEnumerable<ClaimSet> issuedClaimSets;

        public CreditCardTokenAuthorizationPolicy(ClaimSet issuedClaims)
        {
            if (issuedClaims == null)
                throw new ArgumentNullException(nameof(issuedClaims));
            this.issuer = issuedClaims.Issuer;
            this.issuedClaimSets = new ClaimSet[] { issuedClaims };
            this.id = Guid.NewGuid().ToString();
        }

        public ClaimSet Issuer { get { return this.issuer; } }

        public string Id { get { return this.id; } }

        public bool Evaluate(EvaluationContext context, ref object state)
        {
            foreach (ClaimSet issuance in this.issuedClaimSets)
            {
                context.AddClaimSet(this, issuance);
            }

            return true;
        }
    }

Zobrazení informací o volajících

Chcete-li zobrazit informace volajícího, použijte ServiceSecurityContext.Current.AuthorizationContext.ClaimSets vzorový kód, jak je znázorněno v následujícím vzorovém kódu. Obsahuje ServiceSecurityContext.Current.AuthorizationContext.ClaimSets deklarace identity autorizace přidružené k aktuálnímu volajícímu. Deklarace identity jsou poskytovány CreditCardToken třídou v její AuthorizationPolicies kolekci.

bool TryGetStringClaimValue(ClaimSet claimSet, string claimType, out string claimValue)
{
    claimValue = null;
    IEnumerable<Claim> matchingClaims = claimSet.FindClaims(claimType, Rights.PossessProperty);
    if (matchingClaims == null)
        return false;
    IEnumerator<Claim> enumerator = matchingClaims.GetEnumerator();
    enumerator.MoveNext();
    claimValue = (enumerator.Current.Resource == null) ? null :
        enumerator.Current.Resource.ToString();
    return true;
}

string GetCallerCreditCardNumber()
{
     foreach (ClaimSet claimSet in
         ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
     {
         string creditCardNumber = null;
         if (TryGetStringClaimValue(claimSet,
             Constants.CreditCardNumberClaim, out creditCardNumber))
             {
                 string issuer;
                 if (!TryGetStringClaimValue(claimSet.Issuer,
                        ClaimTypes.Name, out issuer))
                 {
                     issuer = "Unknown";
                 }
                 return $"Credit card '{creditCardNumber}' issued by '{issuer}'";
        }
    }
    return "Credit card is not known";
}

Při spuštění ukázky se požadavky na operace a odpovědi zobrazí v okně konzoly klienta. 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 hostované službou IIS, která vyžaduje zabezpečení založené na certifikátech serveru. Tento dávkový soubor musí být upraven tak, aby fungoval v počítačích nebo aby fungoval v případě, že není hostovaný.

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 Setup.bat souboru 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 v tomto dávkovém souboru je localhost. Pokud proměnnou %SERVER_NAME% změníte, musíte projít Client.cs a Service.cs soubory a nahradit všechny instance localhost názvem serveru, který používáte ve skriptu Setup.bat.

    Certifikát je uložený v úložišti My (Personal) pod umístěním LocalMachine úložiště. Certifikát je uložen v úložišti LocalMachine pro služby hostované službou IIS. U služeb v místním prostředí byste měli upravit dávkový soubor tak, aby se klientský certifikát uložil do umístění úložiště CurrentUser nahrazením řetězce LocalMachine aktuálním uživatelem.

    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 generované 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.

    echo ************
    echo copying server cert to client's TrustedPeople store
    echo ************
    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    
  • Pokud chcete povolit přístup k privátnímu klíči certifikátu ze služby hostované službou IIS, musí mít uživatelský účet, pod kterým je spuštěný proces hostované službou IIS, udělena příslušná oprávnění pro privátní klíč. Toho dosáhnete posledním postupem ve skriptu Setup.bat.

    echo ************
    echo setting privileges on server certificates
    echo ************
    for /F "delims=" %%i in ('"%ProgramFiles%\ServiceModelSampleTools\FindPrivateKey.exe" My LocalMachine -n CN^=%SERVER_NAME% -a') do set PRIVATE_KEY_FILE=%%i
    set WP_ACCOUNT=NT AUTHORITY\NETWORK SERVICE
    (ver | findstr /C:"5.1") && set WP_ACCOUNT=%COMPUTERNAME%\ASPNET
    echo Y|cacls.exe "%PRIVATE_KEY_FILE%" /E /G "%WP_ACCOUNT%":R
    iisreset
    

Poznámka:

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

Nastavení a sestavení ukázky

  1. Ujistěte se, že jste pro ukázky windows Communication Foundation provedli jednorázovou instalační proceduru.

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

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

  1. Otevřete okno příkazového řádku sady 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. Ujistěte se, že cesta obsahuje složku, ve které se nachází Makecert.exe.

Poznámka:

Certifikáty nezapomeňte odebrat spuštěním Cleanup.bat po dokončení ukázky. Jiné ukázky zabezpečení používají stejné certifikáty.

  1. Spusťte Client.exe z adresáře client\bin. Aktivita klienta se zobrazí v aplikaci konzoly klienta.

  2. 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čem

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

  2. Zkopírujte soubory programu služby do adresáře služby v počítači služby. Nezapomeňte kopírovat CreditCardFile.txt; jinak ověřovací program platební karty nemůže ověřit informace o platební kartě odeslané z klienta. Zkopírujte také soubory Setup.bat a Cleanup.bat do počítače služby.

  3. Musíte mít certifikát serveru s názvem subjektu, který obsahuje plně kvalifikovaný název domény počítače. Pokud proměnnou změníte %SERVER_NAME% na plně kvalifikovaný název počítače, kde je služba hostovaná, můžete ji vytvořit pomocí Setup.bat. Všimněte si, že soubor Setup.bat musí být spuštěný v příkazovém řádku pro vývojáře pro Visual Studio otevřené s oprávněními správce.

  4. Zkopírujte certifikát serveru do úložiště CurrentUser-Trusted Lidé v klientovi. Musíte to udělat jenom v případě, že certifikát serveru nevystavil důvěryhodný vystavitel.

  5. V souboru EchoServiceHost.cs změňte hodnotu názvu subjektu certifikátu tak, aby místo localhost zadal plně kvalifikovaný název počítače.

  6. Zkopírujte soubory klientského programu ze složky \client\bin\ ve složce specifické pro jazyk do klientského počítače.

  7. V souboru Client.cs změňte hodnotu adresy koncového bodu tak, aby odpovídala nové adrese vaší služby.

  8. V souboru Client.cs změňte název subjektu certifikátu X.509 služby tak, aby odpovídal plně kvalifikovanému názvu počítače vzdáleného hostitele místo místního hostitele.

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

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

  1. Po dokončení spuštění ukázky spusťte Cleanup.bat ve složce s ukázkami.