Übersetzung vorschlagen
 
Andere Vorschläge:

progress indicator
Keine anderen Vorschläge
MSDN Magazin > Home > Ausgaben > 2009 > MSDN Magazin Juli 2009 >  Grundlagen: Sichern des .NET Service Bus
Inhalt anzeigen:  Englisch mit deutscher ÜbersetzungInhalt anzeigen: Englisch mit deutscher Übersetzung
Dies sind maschinell übersetzte Inhalte, die von den Mitgliedern der Community bearbeitet werden können. Sie können die Übersetzung verbessern, indem Sie auf den jeweils zum Satz gehörenden Link "Bearbeiten" klicken.Mithilfe des Dropdown-Steuerelements "Inhalt anzeigen" links oben auf der Seite können Sie zudem bestimmen, ob nur der englische Originaltext, nur die deutsche Übersetzung oder beides nebeneinander angezeigt werden.
Foundations
Securing The .NET Service Bus
Juval Lowy
Code download available from the MSDN Code Gallery
Browse the Code Online
In my April 2009 column, I presented the .NET Services Bus and described how you can utilize relay bindings to connect your application and customers across almost all network boundaries. However, if just anyone were allowed to relay messages to your service, or if any service could receive your client calls, the relay service would be a dangerous proposition. You need to protect the transfer of the message from the client to the service via the relay service. In this column, I show you how to secure the .NET Services Bus and also provide some helper classes and utilities to automate many of the details.
The .NET Services Bus mandates that the service must always authenticate itself to receive relayed messages. Clients, on the other hand, may or may not authenticate themselves. Typically (and by default), clients do authenticate, but the relayed service may decide to waive the client's .NET Services Bus authentication.
The .NET Services Bus offers three different authentication mechanisms—CardSpace, password, or certificate—and it is up to the solution administrator to associate these using the solution page shown in Figure 1.
Figure 1 Configuring Solution Authentication Options
A single solution can support multiple authentication options, and for each option the administrator can add multiple credentials. For example, the administrator might configure three passwords, two cards, and a single certificate. Presenting any one of these credentials is enough to authenticate against the relay service. Also, the service and the client can use different authentication methods. For example, the service can use a password, and the client a certificate.

Configuring Authentication
The enum TransportClientCredentialType, shown here, represents the available credential options:
public enum TransportClientCredentialType
{
   CardSpace,
   UserNamePassword,
   X509Certificate
   Unauthenticated,
   FederationViaCardSpace,
   AutomaticRenewal
}
In TransportClientCredentialType, Client refers to a client of the .NET Services Bus—that is, both the client and the relayed service.
The preferred authentication mechanism and the credentials themselves are configured using an endpoint behavior called TransportClientEndpointBehavior, defined in Figure 2.
public class TransportClientEndpointBehavior : IEndpointBehavior
{
   public TransportClientCredentials Credentials
   {get;}
   public TransportClientCredentialType CredentialType
   {get;set;}
}
public class TransportClientCredentials
{
   public X509CertificateCredential ClientCertificate 
   {get;}
   public UserNamePasswordCredential UserName
   {get;}
}
Using an endpoint behavior (as opposed to a service behavior) provides two advantages. First, a service host can choose a different authentication mechanism for each endpoint. Second, an endpoint behavior offers a unified programming model for the client and the service because the client has only endpoint behaviors.

CardSpace Authentication
CardSpace is the default credential type used by all relay bindings. When the client or the host uses CardSpace authentication, the user is prompted to provide a card on opening either the host or the proxy. After the user provides the card, it is bundled in the connection request message to the relay service. Obviously, such an approach is best suited for interactive applications. These prompts, however, will annoy the user if they occur every time the user opens a new proxy or host. Fortunately, the credential is cached in the app domain, and the user is not prompted again as long as he or she accesses the same endpoint address.

Password Authentication
Like CardSpace authentication, password authentication is best suited for an interactive application, typically in conjunction with a login dialog box. However, there is no need to prompt the user to enter a user name because that is always the solution name. After the user provides the password, you need to programmatically provide the solution name and the password to the TransportClientEndpointBehavior.
On the host side, you need to instantiate a new TransportClientEndpointBehavior object and set the CredentialType property to TransportClientCredentialType.UserNamePassword. The credentials themselves are provided to the Credentials property. You then add this behavior to every endpoint of the host that uses the relay service, as shown in Figure 3.
TransportClientEndpointBehavior behavior = 
           new TransportClientEndpointBehavior();
behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
behavior.Credentials.UserName.UserName = "MySolution";
behavior.Credentials.UserName.Password = "MyPassword";
ServiceHost host = new ServiceHost(typeof(MyService));

foreach(ServiceEndpoint endpoint in host.Description.Endpoints)
{
   endpoint.Behaviors.Add(behavior);
}

host.Open();
You can encapsulate and automate the steps in Figure 3 by using extension methods such as the SetServiceBusPassword methods of my ServiceBusHelper static class, shown here:
public static class ServiceBusHelper
{
   public static void SetServiceBusPassword(this ServiceHost host, string password); 
   public static void SetServiceBusPassword(this ServiceHost host, string solution,string password);
}
Using these extensions, Figure 3 is condensed to the following:
ServiceHost host = new ServiceHost(typeof(MyService));
host.SetServiceBusPassword("MyPassword");
host.Open();
You can see an implementation of the SetServiceBusPassword methods without error handling in the sample code that accompanies this article.
ServiceBusHelper defines the helper private method SetBehavior, which accepts a collection of endpoints and assigns a provided TransportClientEndpointBehavior object to all endpoints in the collection. The private SetServiceBusPassword helper methods accept a collection of endpoints, the solution password, and optionally the solution name. If the solution name is not specified, SetServiceBusPassword extracts it from the address of the first endpoint. SetServiceBusPassword then creates a TransportClientEndpointBehavior, configures it to use the password, and calls SetBehavior. The public SetServiceBusPassword methods simply call the private ones with the collection of endpoints of the host.
The client needs to follow similar steps, except there is only one endpoint to configure—the one the proxy is using, as shown in Figure 4.
TransportClientEndpointBehavior behavior = 
  new TransportClientEndpointBehavior();
behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
behavior.Credentials.UserName.UserName = "MySolution";
behavior.Credentials.UserName.Password = "MyPassword";
MyContractClient proxy = new MyContractClient();
proxy.Endpoint.Behaviors.Add(behavior);

proxy.MyMethod();

proxy.Close();
Again, you should encapsulate this repetitive code with extension methods and offer similar support for working with class factories. Using these extensions, Figure 4 is condensed to this code:
MyContractClient proxy = new MyContractClient();
proxy.SetServiceBusPassword("MyPassword");
proxy.MyMethod();
proxy.Close();
Figure 5 shows the implementation of two of the client-side SetServiceBusPassword<T> extensions. Note the use of the SetServiceBusPassword helper methods by wrapping the single endpoint the proxy has with a collection of endpoints.
public static class ServiceBusHelper
{
   public static void SetServiceBusPassword<T>(this ClientBase<T> proxy,
                                         string password) where T : class
   {
      if(proxy.State == CommunicationState.Opened)
      {
         throw new InvalidOperationException("Proxy is already opened");
      }
      proxy.ChannelFactory.SetServiceBusPassword(password);
   }
     public static void SetServiceBusPassword<T>(this ChannelFactory<T> factory,
                                         string password) where T : class
   {
      if(factory.State == CommunicationState.Opened)
      {
         throw new InvalidOperationException("Factory is already opened");
      }
   Collection<ServiceEndpoint> endpoints = 
                                  new Collection<ServiceEndpoint>();

      endpoints.Add(factory.Endpoint);
      SetServiceBusPassword(endpoints,password);
   }
   //More members 
}
Because TransportClientEndpointBehavior is just another endpoint behavior, you can also configure it in the config file. Storing the password in a text config file, however, is highly inadvisable.

Certificate Authentication
Using a certificate to authenticate against the .NET Service Bus is the best option for noninteractive applications, and you can set the certificate both programmatically and in the config file.
The main hurdle in using certificates is that the certificate must contain a private key, which entails an elaborate setup sequence by the solution administrator. However, once the solution is configured to use the certificate, the rest of the work is straightforward.
Both the client and the service host use identical configuration entries, as shown in Figure 6.
      <endpoint behaviorConfiguration = "RelayCert"
         ...
      />
...
<behaviors>
   <endpointBehaviors>
      <behavior name = "RelayCert">
        <transportClientEndpointBehavior credentialType =
                                                   "X509Certificate">
            <clientCredentials>
               <clientCertificate
                  findValue     = "MyRelayCert"
                  storeLocation = "LocalMachine"
                  storeName     = "My"
                  x509FindType  = "FindBySubjectName"
               />
            </clientCredentials>
         </transportClientEndpointBehavior>
      </behavior>
   </endpointBehaviors>
</behaviors>
To programmatically provide the certificate on the host side, you need to follow steps similar to those shown earlier in Figure 3. Besides setting the credentials type to TransportClientCredentialType.X509Certificate, you need to use the SetCertificate method of the ClientCertificate property on Credentials. Here again, you can streamline it using host extension methods, as shown here:
public static class ServiceBusHelper
{
   public static void SetServiceBusCertificate(this ServiceHost host);
   public static void SetServiceBusCertificate(this ServiceHost host, string subjectName);
   public static void SetServiceBusCertificate(this ServiceHost host, object findValue,StoreLocation location,
      StoreName storeName,X509FindType findType);
   //More members
}
For example:
ServiceHost host = new ServiceHost(typeof(MyService));
host.SetServiceBusCertificate("MyRelayCert");
host.Open();
SetServiceBusCertificate defaults the store to MyComputer and the location to My, and it looks up the certificate by name. SetServiceBusCertificate also extracts the solution name from the host endpoints.
The client can also programmatically provide the certificate to use to the proxy by following steps similar to Figure 4, and you can automate this by using these extension methods, which follow the same default values discussed for the host:
public static class ServiceBusHelper
{
  public static void SetServiceBusCertificate<T>(this ClientBase<T> proxy) 
                       where T : class;
  public static void SetServiceBusCertificate<T>(this ClientBase<T> proxy,
                       string subjectName) where T : class;
  public static void SetServiceBusCertificate<T>(this ClientBase<T> proxy,
                       object findValue,StoreLocation location,StoreName
                       storeName,X509FindType findType) where T : class;
   //Similar methods for a channel factory
}
Using the extensions on the client side yields this code:
MyContractClient proxy = new MyContractClient();
proxy.SetServiceBusCertificate("MyRelayCert");
proxy.MyMethod();
proxy.Close();

No Authentication
Although the service must always authenticate against the service bus, you might decide to exempt the client and allow it unauthenticated access to the relay service. In that case, the client must set TransportClientEndpointBehavior to TransportClientCredentialType.Unauthenticated. When the clients are not authenticated by the relay service, it is now up to the relayed service to authenticate the clients. The downside is that the service is now less shielded than when the relay service authenticated clients. In addition, you must use message security to transfer the client credentials (as discussed later). To enable unauthenticated access by the client, both the service and the client must explicitly allow it by configuring the relay binding to not authenticate, using the enum RelayClientAuthenticationType, shown here:
public enum RelayClientAuthenticationType
{
   RelayAccessToken, //Default
   None
}
You assign that enum via the Security property.

Transfer Security
The next crucial aspect of security is how to securely transfer the message through the relay to the service. In addition to message transfer security, another important design decision is which client credentials (if any) the message should contain. Transfer security is independent of how the client or the service authenticates itself against the .NET Service Bus.
The .NET Services Bus offers four options for transfer security, represented by the enum EndToEndSecurityMode:
public enum EndToEndSecurityMode
{
   None,
   Transport,
   Message,
   TransportWithMessageCredential //Mixed
}
The four options are None, Transport, Message, and Mixed. None means just that—the message is not secured at all. Transport uses SSL or HTTPS to secure the message transfer. Message security encrypts the body of the message so that it can be sent over nonsecured transports. Mixed uses message security to contain the client's credentials but transfers the message over a secured transport. Figure 7 shows the way the relay binding supports the various transfer security modes and their default values. A bold plus sign (+) marks defaults.
Figure 7 Binding and Transfer Security
Binding None Transport Message Mixed
TCP (Relayed) + + + +
TCP (Direct/Hybrid) + - + -
WS + + + +
One-Way + + + -
You configure transfer security in the binding. Although the relay bindings use different default values, all the relay bindings offer at least one constructor that takes EndToEndSecurityMode as a construction parameter. You can also configure transfer security after construction by accessing the Security property and its Mode property.

Transport Security
When it comes to transfer security, transport security is the simplest to set up and configure. When using transport security, all client calls are anonymous—the client messages do not contain any client credentials. While transport security is the easiest to use, it does not provide end-to-end security. It secures only the transfer of the message to the relay service and from the relay service. The journey inside the relay service is not secured.
This means that in theory, the relay service can eavesdrop on the communication between the client and the service and even tamper with the messages. However, I believe that in practice this is impractical given the volume of traffic to the .NET Services Bus. Simply put, this kind of subversion cannot be performed as an aside and requires dedicated resources, planning, staff, and technology. In addition, Microsoft has proven over the years that it has the highest integrity and respect for its customers' privacy, and it has many other areas it could have abused if it were indeed malicious.

Message Security
Message security encrypts the body of the message using a service-provided certificate. Because the message itself is protected rather than the transport, the journey inside the relay is protected as well. The downside to message security is that it requires additional setup steps.
While I think that in practice transport security is enough, it is vital to assure customers and users of the presence of end-to-end privacy and integrity and to guard against even theoretical compromises. I therefore recommend always relying on message security for all relayed communication, which will also provide additional benefits, such as direct connection and the availability of security call context to the service.
Unlike in transport security, in message security the message might contain the client's credentials. The primary use of client credentials by the service is for local authorization of the call to establish some role-based security policy. Whenever the message contains credentials, the service must also authenticate them (even if all it wants is to authorize the client). Note that such authentication is on top of the authentication the relay service has already performed. If the relay service has already authenticated the client, authenticating the call again by the service does not add much in the way of security, yet it burdens the service with managing the client's credentials. If the relay service is not authenticating the client, the service will be subjected to all the unwanted traffic of unauthenticated clients, which could have severe IT operations implications.
For these reasons, I find that the best practice is for the relay service to authenticate the client and to avoid having the service do it again. You should also design your service so that it has no need for the client's credentials. Such a design is aligned with the chain-of-trust design pattern that works well in a layered architecture. That said, there are cases when the service needs the client credentials for a local use other than authorization, such as personalization, auditing, or proprietary integration with legacy systems.

TCP Relay Binding and Transfer Security
The TCP relay binding defaults to transport security, and no special configuration steps are required. It simply uses SSL over port 828. When using transport security, however, you can only use the TCP relay binding connection mode of TcpRelayConnectionMode.Relayed.
Because the call is anonymous, on the service side Windows Communication Foundation (WCF) attaches a generic principal with a blank identity to the thread executing the call, and the ServiceSecurityContext is null.
To protect the transfer of the message, you must configure the service host with a certificate. The client will by default negotiate the certificate (obtain its public key), so there is no need to explicitly list the certificate in the client's config file. However, the client still needs to validate the negotiated certificate. As with regular WCF and message security, the best practice is to validate the certificate using peer-trust, which means installing the certificate beforehand in the client's Trusted People folder. Besides providing true end-to-end transfer security over the relay, using message security also enables the use of the direct and hybrid connection modes.
As discussed previously, the message might or might not contain the client's credentials. If you avoid sending the credentials in the message, WCF will attach to the thread executing the call a Windows principal with a blank identity, which does not make much sense. When using message security without credentials, you should also set the host PrincipalPermissionMode to None to get the same principal as with transport security. To configure the binding for message security with anonymous calls, use MessageCredentialType.None and assign that value to the ClientCredentialType property of MessageSecurityOverRelayConnection, available in the Message property of NetTcpRelaySecurity. Figure 8 shows code that demonstrates this.
public sealed class NetTcpRelaySecurity
{
   public EndToEndSecurityMode Mode 
   {get;set;}
   public MessageSecurityOverRelayConnection Message
   {get;}
   //More members
}
public sealed class MessageSecurityOverRelayConnection
{
   public MessageCredentialType ClientCredentialType
   {get;set;}
   //More members
}
Figure 9 shows the required host-side config file.
  <service name = "..." behaviorConfiguration = "MessageSecurity">
      <endpoint
         ...
         binding  = "netTcpRelayBinding"
         bindingConfiguration = "MessageSecurity"
      />
   </service>
   ...
      <serviceBehaviors>
         <behavior name = "MessageSecurity">
            <serviceCredentials>
               <serviceCertificate
                  findValue     = "MyServiceCert"
                  storeLocation = "LocalMachine"
                  storeName     = "My"
                  x509FindType  = "FindBySubjectName"
               />
            </serviceCredentials>
            <serviceAuthorization principalPermissionMode ="None"/>
         </behavior>
      </serviceBehaviors>
   <bindings>
      <netTcpRelayBinding>
         <binding name = "MessageSecurity">
            <security mode = "Message">
               <message clientCredentialType = "None"/>
            </security>
         </binding>
      </netTcpRelayBinding>
   </bindings>
On the client side, you must include the service certificate name in the address identity of the endpoint because that name does not match the relay service domain. Figure 10 shows the required config file.
<client>
   <endpoint behaviorConfiguration = "ServiceCertificate"
      binding  = "netTcpRelayBinding"
      bindingConfiguration = "MessageSecurity"
      <identity>
         <dns value = "MyServiceCert"/>
      </identity>
      ...
   </endpoint>
</client>
<bindings>
   <netTcpRelayBinding>
      <binding name = "MessageSecurity">
         <security mode = "Message">
            <message clientCredentialType = "None"/>
         </security>
      </binding>
   </netTcpRelayBinding>
</bindings>
<behaviors>
   <endpointBehaviors>
      <behavior name = "ServiceCertificate">
         <clientCredentials>
            <serviceCertificate>
               <authentication certificateValidationMode= "PeerTrust"/>
            </serviceCertificate>
         </clientCredentials>
      </behavior>
   </endpointBehaviors>
</behaviors>
If you want to include the client credentials in the message, the service must also authenticate those credentials, using the same setting as with regular TCP calls. In that case, the service principal and primary identity will both have an identity matching those credentials. The credential can be a user name and password, a certificate, or an issued token. You must indicate to both the host and the client in the binding which credential types you expect. For example, for user name credentials, use the following:
<bindings>
   <netTcpRelayBinding>
      <binding name = "MessageSecurity">
         <security mode = "Message">
            <message clientCredentialType = "UserName"/>
         </security>
      </binding>
   </netTcpRelayBinding>
</bindings>
On the host side, if the credentials are user name and password, you must also configure, using behaviors, how to authenticate and authorize the credentials. The default will be Windows credentials, but the more common choice would be using some credentials store such as the ASP.NET providers:
<service name = "..." behaviorConfiguration = "CustomCreds">
   ...
</service>
...
<serviceBehaviors>
   <behavior name = "CustomCreds">
      <serviceCredentials>
         <userNameAuthentication 
            userNamePasswordValidationMode = "MembershipProvider"
         />
      </serviceCredentials>
      <serviceAuthorization principalPermissionMode = "UseAspNetRoles"/>
   </behavior>
</serviceBehaviors>
The client has to populate the proxy with the credentials. When using a username and password, the client code would be insert like this:
MyContractClient proxy = new MyContractClient();
proxy.ClientCredentials.UserName.UserName = "MyUserName";
proxy.ClientCredentials.UserName.Password = "MyPassword";

proxy.MyMethod();

proxy.Close();
The client has no way of knowing if the credentials it provides are authenticated on the service side as Windows or custom credentials.
Mixed transfer security is the only way to avoid anonymous calls over transport security. Since transport security cannot pass credentials, you pass the credentials using message security, hence the term mixed. When using mixed transfer security over the TCP relay binding you are restricted to using only relayed connections.
Figure 11 shows how to configure either the service or the client for mixed security.
   <endpoint
      binding  = "netTcpRelayBinding"
      bindingConfiguration = "MixedSecurity"
      ...
   />
...
<bindings>
   <netTcpRelayBinding>
      <binding name = "MixedSecurity">
         <security mode = "TransportWithMessageCredential"/>
      </binding>
   </netTcpRelayBinding>
</bindings>
After the messages are received by the service, the host must authenticate the calls as with regular TCP. Once authenticated, the service call will have a principal object matching the credentials provided and a security call context.

WS Relay Binding and Transfer Security
Combining the WS binding with transport security is as easy as changing the address schema from HTTP to HTTPS and setting the binding to use transport security, as shown in Figure 12.
   <endpoint
     address  = "https://MySolution.servicebus.windows.net/..."
     binding  = "wsHttpRelayBinding"
     bindingConfiguration = "TransportSecurity"
     ...
   />

<bindings>
   <wsHttpRelayBinding>
      <binding name = "TransportSecurity">
         <security mode = "Transport"/>
      </binding>
   </wsHttpRelayBinding>
</bindings>
Note that the WS relay binding defaults to using message security for transfer security. Since message security requires additional configuration steps, the WS relay binding does not work as-is out of the box, and all calls will fail. However, configuring the WS relay binding to use message (or mixed) security is identical to configuring the TCP relay binding.

One-Way Relay Binding and Transfer Security
The one-way relay binding (and its subclasses) is the only binding that defaults to having no transfer security at all. In addition, it does not support mixed transfer security. Configuring it to use transport security is the same as with the TCP and WS relay bindings. Configuring it to use message security is similar but with one important difference—the one-way relay binding cannot negotiate the service certificate because there may not even be a service, and no direct interaction with the service takes place. When using message security on the client, you must explicitly specify the service certificate, as shown in Figure 13.
<client>
   <endpoint behaviorConfiguration = "ServiceCertificate"
      ...
   </endpoint>
</client>

<behaviors>
   <endpointBehaviors>
      <behavior name = "ServiceCertificate">
         <clientCredentials>
            <serviceCertificate>
               <scopedCertificates>
                  <add targetUri = "sb://MySolution.servicebus..."
                     findValue     = "MyServiceCert"
                     storeLocation = "LocalMachine"
                     storeName     = "My"
                     x509FindType  = "FindBySubjectName"                        
                  />
               </scopedCertificates>
            </serviceCertificate>
         </clientCredentials>
      </behavior>
   </endpointBehaviors>
</behaviors>
Another important distinction between the one-way relay binding and the other relay bindings is that if the call is anonymous, with either transport or message security, the call has a security call context whose primary identity is
service bus certificate CN=servicebus.windows.net. 

Streamlining Transfer Security
While transfer security offers a slew of details and intricate options, you can and should streamline and automate most of these security configuration decisions. To encapsulate it on the host side, use my ServiceBusHost class, defined as insert the following:
public class ServiceBusHost : ServiceHost
{
   public ServiceBusHost(object singletonInstance, params Uri[] baseAddresses);
   public ServiceBusHost(Type serviceType,params Uri[] baseAddresses);

   public void ConfigureAnonymousMessageSecurity(string serviceCert);
   public void ConfigureAnonymousMessageSecurity(string serviceCert,
                            StoreLocation location,StoreName storeName);
   public void ConfigureAnonymousMessageSecurity(StoreLocation location,
            StoreName storeName,X509FindType findType,object findValue);

   //More members
}
When using ServiceBusHost, no other setting in config or in code is required. Per my recommendation, you can use the ConfigureAnonymousMessageSecurity method to enable anonymous calls over message security. All you need to provide it is the certificate name to use:
ServiceBusHost host = new ServiceBusHost(typeof(MyService));
host.ConfigureAnonymousMessageSecurity("MyServiceCert");
host.Open();
ConfigureAnonymousMessageSecurity will default the certificate location to the local machine and the certificate store to My, and it will look up the certificate by its common name. If you do not call ConfigureAnonymousMessageSecurity, ServiceBusHost will default to using anonymous message security with the solution name for the certificate name:
ServiceBusHost host = new ServiceBusHost(typeof(MyService));
host.Open();
You can also use the overloaded versions that let you explicitly specify some or all of the certificate details.
ServiceBusHost makes use of the ConfigureBinding method of ServiceBusHelper. ConfigureBinding defaults to anonymous calls. If the calls are to have credentials, ConfigureBinding always uses username credentials. With the TCP relay binding, ConfigureBinding uses the hybrid connection mode. ConfigureBinding also always enables reliable messages.
ServiceBusHost also supports message security with credentials via the ConfigureMessageSecurity methods:
public class ServiceBusHost : ServiceHost
{
   public void ConfigureMessageSecurity();
   public void ConfigureMessageSecurity(string serviceCert);
   public void ConfigureMessageSecurity(string serviceCert,
                                        string applicationName);
   public void ConfigureMessageSecurity(string serviceCert,
                                        bool useProviders,
                                        string applicationName);
   //More members
}
ConfigureMessageSecurity defaults to using the ASP.NET membership providers, but it can be instructed to use Windows accounts as well. The implementation of ConfigureMessageSecurity is similar to that of ConfigureAnonymousMessageSecurity.
You can provide clients with an easy way of configuring message security with my ServiceBusClientBase<T>, defined as
public abstract class ServiceBusClientBase<T> : ClientBase<T> where T : class
{
   public ServiceBusClientBase();
   public ServiceBusClientBase(string endpointName);
   public ServiceBusClientBase(Binding binding,
                               EndpointAddress remoteAddress);
   public ServiceBusClientBase(string username,string password);

   public ServiceBusClientBase(string endpointName,
                               string username,string password);
   public ServiceBusClientBase(Binding binding,EndpointAddress address,
                               string username,string password);

   protected virtual void ConfigureForServiceBus();
   protected virtual void ConfigureForServiceBus(string username, string password);

}
ServiceBusClientBase<T> offers two sets of constructors. The constructors that merely take the endpoint parameters all default to using message security with anonymous calls. You can also use the constructors that accept the username and password credentials. If no endpoint address identity is provided, ServiceBusClientBase<T> defaults it to the solution name. You use ServiceBusClientBase<T> like the WCF-provided ClientBase<T>:
[ServiceContract]
interface IMyContract
{
   [OperationContract]
   void MyMethod();
}
class MyContractClient : ServiceBusClientBase<IMyContract>,IMyContract
{
   public MyContractClient()
   {}
   public void MyMethod()
   {
      Channel.MyMethod();
   }
}
The sample code download includes the full implementation of ServiceBusClientBase<T>. ServiceBusClientBase<T> uses peer-trust to validate the service certificate. The bulk of the work is done by passing the endpoint binding to ServiceBusHelper.ConfigureBinding.
The one remaining sore point is the one-way relay binding, with its lack of certificate negotiation. To alleviate that, I wrote OneWayClientBase<T>:
public abstract class OneWayClientBase<T> : ServiceBusClientBase<T>   where T : class
{
   //Same constructors as ServiceBusClientBase<T> 

   public void SetServiceCertificate(string serviceCert);
   public void SetServiceCertificate(string serviceCert,
                                     StoreLocation location,
                                     StoreName storeName);
   public void SetServiceCertificate(object findValue,
        StoreLocation location,StoreName storeName,X509FindType findType);
}
OneWayClientBase<T> derives from ServiceBusClientBase<T> and adds the SetServiceCertificate methods. If you never call SetServiceCertificate, OneWayClientBase<T> simply looks up the service certificate from config. SetServiceCertificate offers a simple programmatic way of avoiding the config altogether. It even sets the identity tag of the endpoint address. SetServiceCertificate uses the same defaults as ServiceBusHost, including using the solution name for the certificate name if no certificate is provided. Here's how you use OneWayClientBase<T> :
class MyContractClient : OneWayClientBase<IMyContract>,IMyContract
{
   public MyContractClient() 
   {}
   public void MyMethod()
   {
      Channel.MyMethod();
   }
}

MyContractClient proxy = new MyContractClient();
proxy.SetServiceCertificate("MyServiceCert");

proxy.MyMethod();

proxy.Close();
As you can see, using OneWayClientBase<T> is straightforward.

Send your questions and comments to mmnet30@microsoft.com.

Juval Lowy a software architect with IDesign providing WCF training and architecture consulting. His recent book is Programming WCF Services 2nd Edition (O'Reilly, 2008). He is also the Microsoft Regional Director for the Silicon Valley. Contact Juval at www.idesign.net.

Grundlagen
Sichern des .NET Service Bus
Juval Lowy
Herunterladen von Code von der MSDN Code Gallery verfügbar
Code online durchsuchen
In meinem Artikel vom April 2009 ich der .NET Services Bus dargestellt und beschrieben, wie Sie Relay Bindungen Verbindung von Ihrer Anwendung und Kunden über fast alle Netzwerkgrenzen nutzen können. Jedoch würde Wenn nur jemand Weitergabe von Nachrichten zu Ihrem Dienst zulässig waren oder jeden Dienst Ihre Client-Anrufe empfangen kann, der Relay-Dienst eine gefährliche Angelegenheit sein. Sie müssen die Übertragung der Nachricht vom Client an den Dienst über den Dienst Relay zu schützen. In dieser Kolumne zeige ich Ihnen zum Sichern der Bus .NET Services sowie auch bieten einige Hilfsklassen und Dienstprogramme zum Automatisieren viele der Details.
Der .NET Services Bus erfordert, dass der Dienst immer sich weitergeleitete Nachrichten empfangen authentifizieren muss. Clients, können andererseits, oder können nicht sich selbst authentifizieren. In der Regel (und in der Standardeinstellung) Clients authentifizieren, aber der Dienst weitergeleitete kann entscheiden, Clientauthentifizierung .NET Services Bus verzichten.
Der Bus .NET Services bietet drei verschiedene Authentifizierungsmechanismen, CardSpace, Kennwort oder Zertifikat – und es ist der Lösung Administrator Zuordnen dieser Lösung auf der Seite im Abbildung 1 angezeigt.
Abbildung 1 Projektmappen Authentifizierungsoptionen konfigurieren
Eine einzelne Projektmappe kann mehrere Authentifizierungsoptionen unterstützen, und für jede Option der Administrator kann mehrere Anmeldeinformationen hinzufügen. Der Administrator könnte z. B. drei Kennwörter, zwei Karten und ein einzelnes Zertifikat konfigurieren. Präsentieren eine der folgenden Anmeldeinformationen ist ausreichend, sich bei der Relay-Dienst zu authentifizieren. Außerdem können der Dienst und der Client unterschiedliche Authentifizierungsmethoden verwenden. Der Dienst kann z. B. ein Kennwort und der Client ein Zertifikat verwenden.

Konfigurieren der Authentifizierung
Die Enumeration TransportClientCredentialType, hier, stellt die Optionen zur Verfügung Anmeldeinformationen:
public enum TransportClientCredentialType
{
   CardSpace,
   UserNamePassword,
   X509Certificate
   Unauthenticated,
   FederationViaCardSpace,
   AutomaticRenewal
}
In TransportClientCredentialType, Client ein Client das .NET Services Bus bezeichnet –, dem Client und der Dienst weitergeleitete.
Der bevorzugte Authentifizierungsmechanismus und die Anmeldeinformationen selbst werden mit Endpunktverhalten aufgerufen, TransportClientEndpointBehavior, definiert in Abbildung 2 konfiguriert.
public class TransportClientEndpointBehavior : IEndpointBehavior
{
   public TransportClientCredentials Credentials
   {get;}
   public TransportClientCredentialType CredentialType
   {get;set;}
}
public class TransportClientCredentials
{
   public X509CertificateCredential ClientCertificate 
   {get;}
   public UserNamePasswordCredential UserName
   {get;}
}
Mithilfe einer Endpunktverhalten (im Gegensatz zu einer Dienstverhalten) bietet zwei Vorteile. Erstens können ein Host-Dienst einen anderen Authentifizierungsmechanismus für jeden Endpunkt. Zweitens bietet Endpunktverhalten ein einheitliches Programmiermodell für den Client und den Dienst, da der Client nur Endpunktverhaltensweisen verfügt.

CardSpace-Authentifizierung
CardSpace wird standardmäßig Anmeldeinformationen die Art von Bindungen für alle Relay verwendet. Wenn der Client oder die Host CardSpace-Authentifizierung verwendet, wird der Benutzer aufgefordert, an eine Karte, auf die Host oder der Proxy öffnen. Nachdem der Benutzer die Karte bietet, wird es in der Anforderungsnachricht Verbindung an den Relay-Dienst gebündelt. Ein solcher Ansatz ist natürlich für interaktive Anwendungen am besten geeignet. Diese Eingabeaufforderungen werden den Benutzer jedoch ärgern, sofern diese auftreten jedes Mal der Benutzer einen neuen Proxy oder Host öffnet. Glücklicherweise werden die Anmeldeinformationen in der Anwendungsdomäne zwischengespeichert, und der Benutzer wird nicht erneut aufgefordert, solange er die gleichen Endpunktadresse zugreift.

Kennwortauthentifizierung
Wie CardSpace-Authentifizierung ist die Kennwortauthentifizierung für eine interaktive Anwendung in der Regel in Verbindung mit einem Anmeldedialogfeld am besten geeignet. Jedoch besteht keine Notwendigkeit auffordern den Benutzer einen Benutzernamen eingeben, da, immer der Projektmappenname der ist. Nachdem der Benutzer das Kennwort bereitstellt, müssen Sie programmgesteuert den Namen der Projektmappe und das Kennwort für den TransportClientEndpointBehavior bereitstellen.
Auf der Seite Host müssen Sie ein neues TransportClientEndpointBehavior-Objekt instanziiert, und legen Sie die Eigenschaft CredentialType auf TransportClientCredentialType.UserNamePassword. Die Credentials-Eigenschaft werden die Anmeldeinformationen selbst bereitgestellt. Fügen Sie dann dieses Verhalten zur jeder Endpunkt des Host, die der Relay-Dienst verwendet wie in Abbildung 3 dargestellt.
TransportClientEndpointBehavior behavior = 
           new TransportClientEndpointBehavior();
behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
behavior.Credentials.UserName.UserName = "MySolution";
behavior.Credentials.UserName.Password = "MyPassword";
ServiceHost host = new ServiceHost(typeof(MyService));

foreach(ServiceEndpoint endpoint in host.Description.Endpoints)
{
   endpoint.Behaviors.Add(behavior);
}

host.Open();
Sie können kapseln und automatisieren die Schritte im Abbildung 3 mithilfe Erweiterung Methoden wie die Methoden SetServiceBusPassword Meine ServiceBusHelper-statische-Klasse, hier:
public static class ServiceBusHelper
{
   public static void SetServiceBusPassword(this ServiceHost host, string password); 
   public static void SetServiceBusPassword(this ServiceHost host, string solution,string password);
}
Mithilfe dieser Erweiterungen ist die folgende Abbildung 3 komprimiert werden:
ServiceHost host = new ServiceHost(typeof(MyService));
host.SetServiceBusPassword("MyPassword");
host.Open();
Sie können eine Implementierung der SetServiceBusPassword-Methoden anzeigen, ohne Fehlerbehandlung im Beispielcode, der diesen Artikel begleitet.
ServiceBusHelper definiert die Helfer private Methode SetBehavior, die akzeptiert einer Sammlung von Endpunkten und allen Endpunkten in der Auflistung ein bereitgestellten TransportClientEndpointBehavior-Objekt zugewiesen werden. Die privaten SetServiceBusPassword Hilfsmethoden akzeptiert eine Sammlung von Endpunkten, das Lösung-Kennwort und optional den Namen der Projektmappe. Wenn der Namen der Projektmappe nicht angegeben wird, extrahiert SetServiceBusPassword Sie die Adresse des ersten Endpunkts. SetServiceBusPassword dann eine TransportClientEndpointBehavior erstellt, konfiguriert, dass das Kennwort verwenden und SetBehavior aufruft. Die öffentlichen Methoden SetServiceBusPassword rufen einfach privaten diejenigen mit der Auflistung der Endpunkte von der Host.
Der Client muss ähnliche Schritte befolgen, jedoch nur einen Endpunkt konfigurieren, der der Proxy verwendet, wie in Abbildung 4 dargestellt.
TransportClientEndpointBehavior behavior = 
  new TransportClientEndpointBehavior();
behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
behavior.Credentials.UserName.UserName = "MySolution";
behavior.Credentials.UserName.Password = "MyPassword";
MyContractClient proxy = new MyContractClient();
proxy.Endpoint.Behaviors.Add(behavior);

proxy.MyMethod();

proxy.Close();
Erneut sollten Sie sich wiederholende Code mit Erweiterungsmethoden kapseln und bieten ähnliche Unterstützung für das Arbeiten mit Class Factories. Mit diesen Erweiterungen, Abbildung 4 ist an diesem Code komprimiert:
MyContractClient proxy = new MyContractClient();
proxy.SetServiceBusPassword("MyPassword");
proxy.MyMethod();
proxy.Close();
Abbildung 5 zeigt die Implementierung von zwei Client-SetServiceBusPassword, < T >Erweiterungen. Hinweis die Verwendung der SetServiceBusPassword-Hilfsmethoden durch Einschließen des einzelnen Endpunkts der Proxy hat eine Auflistung von Endpunkten.
public static class ServiceBusHelper
{
   public static void SetServiceBusPassword<T>(this ClientBase<T> proxy,
                                         string password) where T : class
   {
      if(proxy.State == CommunicationState.Opened)
      {
         throw new InvalidOperationException("Proxy is already opened");
      }
      proxy.ChannelFactory.SetServiceBusPassword(password);
   }
     public static void SetServiceBusPassword<T>(this ChannelFactory<T> factory,
                                         string password) where T : class
   {
      if(factory.State == CommunicationState.Opened)
      {
         throw new InvalidOperationException("Factory is already opened");
      }
   Collection<ServiceEndpoint> endpoints = 
                                  new Collection<ServiceEndpoint>();

      endpoints.Add(factory.Endpoint);
      SetServiceBusPassword(endpoints,password);
   }
   //More members 
}
Da TransportClientEndpointBehavior nur eine andere Endpunktverhalten ist, können Sie auch in der Konfigurationsdatei konfigurieren. Das Kennwort in einer Text-Konfigurationsdatei zu speichern, ist jedoch sehr inadvisable.

Zertifikatauthentifizierung
Die beste Option für nicht interaktive Anwendungen mit, dass ein Zertifikat für den .NET Service Bus authentifizieren ist und Sie können das Zertifikat festlegen, programmgesteuert und in der Konfigurationsdatei.
Main Hürde mit Zertifikaten ist, dass das Zertifikat einen privaten Schlüssel enthalten muss, der ein umfangreiches Setupsequenz vom Administrator Lösung umfasst. Sobald die Lösung für die Verwendung des Zertifikats konfiguriert ist, ist jedoch die restlichen die Arbeit unkompliziert.
Dem Client und Dienst-Host verwenden eine identische Konfigurationseinträge, wie in Abbildung 6 dargestellt.
      <endpoint behaviorConfiguration = "RelayCert"
         ...
      />
...
<behaviors>
   <endpointBehaviors>
      <behavior name = "RelayCert">
        <transportClientEndpointBehavior credentialType =
                                                   "X509Certificate">
            <clientCredentials>
               <clientCertificate
                  findValue     = "MyRelayCert"
                  storeLocation = "LocalMachine"
                  storeName     = "My"
                  x509FindType  = "FindBySubjectName"
               />
            </clientCredentials>
         </transportClientEndpointBehavior>
      </behavior>
   </endpointBehaviors>
</behaviors>
Um programmgesteuert das Zertifikat auf der Seite Host bereitstellen, müssen Sie diese zuvor in Abbildung 3 ähnelt Schritte. Neben den Anmeldeinformationentyp auf TransportClientCredentialType.X509Certificate festlegen, müssen Sie die SetCertificate-Methode der ClientCertificate-Eigenschaft auf Anmeldeinformationen verwenden. Hier können erneut, Sie mit Host-Erweiterungsmethoden optimieren wie hier gezeigt:
public static class ServiceBusHelper
{
   public static void SetServiceBusCertificate(this ServiceHost host);
   public static void SetServiceBusCertificate(this ServiceHost host, string subjectName);
   public static void SetServiceBusCertificate(this ServiceHost host, object findValue,StoreLocation location,
      StoreName storeName,X509FindType findType);
   //More members
}
Beispiel:
ServiceHost host = new ServiceHost(typeof(MyService));
host.SetServiceBusCertificate("MyRelayCert");
host.Open();
SetServiceBusCertificate wird standardmäßig der Informationsspeicher auf Arbeitsplatz und den Speicherort der, und es aussieht, bis das Zertifikat nach Namen. SetServiceBusCertificate extrahiert den Namen der Projektmappe auch die Endpunkte des Host.
Der Client kann das Zertifikat für den Proxy mithilfe Schritte ähnelt Abbildung 4 auch programmgesteuert bereitstellen, und Sie können dies automatisieren, indem diese Erweiterungsmethoden, die dieselben Standardwerte für die Host behandelt folgen:
public static class ServiceBusHelper
{
  public static void SetServiceBusCertificate<T>(this ClientBase<T> proxy) 
                       where T : class;
  public static void SetServiceBusCertificate<T>(this ClientBase<T> proxy,
                       string subjectName) where T : class;
  public static void SetServiceBusCertificate<T>(this ClientBase<T> proxy,
                       object findValue,StoreLocation location,StoreName
                       storeName,X509FindType findType) where T : class;
   //Similar methods for a channel factory
}
Mit den Erweiterungen auf dem Client führt dieser Code:
MyContractClient proxy = new MyContractClient();
proxy.SetServiceBusCertificate("MyRelayCert");
proxy.MyMethod();
proxy.Close();

Keine Authentifizierung
Obwohl der Dienst immer Service Bus authentifizieren muss, empfiehlt es sich ausgenommen den Client und ermöglichen es nicht authentifizierten Zugriff auf den Relay-Dienst. In diesem Fall muss der Client TransportClientEndpointBehavior auf TransportClientCredentialType.unauthenticated festgelegt. Wenn die Clients vom Relay-Dienst nicht authentifiziert sind, ist es jetzt bis zu dem weitergeleitete Dienst zum Authentifizieren des Clients. Der Nachteil ist, dass der Dienst als jetzt weniger abgeschirmte ist, wenn der Relay-Dienst Clients authentifiziert. Darüber hinaus müssen Sie Nachrichtensicherheit verwenden, um die Clientanmeldeinformationen (wie weiter unten behandelt) übertragen. Um nicht authentifizierten Zugriff vom Client zu aktivieren, müssen dem Webdienst und der Client explizit es zulassen durch die Bindung an nicht authentifizieren, Weiterleitung konfigurieren mithilfe der Enumeration RelayClientAuthenticationType, die hier gezeigte:
public enum RelayClientAuthenticationType
{
   RelayAccessToken, //Default
   None
}
Sie weisen die Enumeration über die Security-Eigenschaft.

Übertragen von Sicherheit
Der nächste wichtige Aspekt Sicherheit ist wie die Nachricht über die Weiterleitung an den Dienst sicher übertragen. Zusätzlich zur Übertragung Nachrichtensicherheit sollte eine andere wichtige Entwurf Entscheidung ist der Client (ggf.) Anmeldeinformationen die Nachricht enthalten. Übertragungssicherheit ist unabhängig von wie der Client oder der Dienst selbst mit den .NET Service Bus authentifiziert.
Der .NET Services Bus bietet vier Optionen für die Übertragungssicherheit, dargestellt durch die Enumeration EndToEndSecurityMode:
public enum EndToEndSecurityMode
{
   None,
   Transport,
   Message,
   TransportWithMessageCredential //Mixed
}
Die vier Optionen sind None, Transport, Message und gemischt. Keine bedeutet lediglich, dass – die Nachricht ist überhaupt nicht gesichert. Transport verwendet SSL oder HTTPS, um die Nachrichtenübertragung zu sichern. Nachrichtensicherheit verschlüsselt Hauptteil der Nachricht, sodass es über nicht gesicherten Transport gesendet werden kann. Gemischte verwendet message Security Anmeldeinformationen des Clients jedoch überträgt die Nachricht über einen gesicherten Transport enthalten. Abbildung 7 zeigt die Art der Relay-Bindung der verschiedenen Übertragungsmodi Sicherheit und deren Standardwerte unterstützt. Ein fett Pluszeichen (+) markiert Standardwerte.
Abbildung 7 binden und übertragen Sicherheit
Bindung Keine Aktion Transport Nachricht Gemischte
TCP (Relay) + + + +
TCP (Direct/Hybrid) + - + -
WS + + + +
Unidirektionale + + + -
Konfigurieren der Übertragungssicherheit in der Bindung. Obwohl die Relay-Bindungen unterschiedliche Standardwerte verwenden, bieten die Relay-Bindungen mindestens einen Konstruktor, der EndToEndSecurityMode als Konstruktion Parameter akzeptiert. Sie können auch die nach der Erstellung Übertragungssicherheit konfigurieren, durch Zugriff auf die Security-Eigenschaft und die Mode-Eigenschaft.

Transportsicherheit
Wenn es zum Übertragen von Sicherheit kommt, ist Transportsicherheit am einfachsten zu einrichten und konfigurieren. Wenn Sie Transportsicherheit verwenden, sind alle Clientaufrufe anonyme – die Client Nachrichten enthalten keine Clientanmeldeinformationen. Transportsicherheit am einfachsten zu verwenden ist, bietet es keine End-to-End-Sicherheit. Es sichert nur die Übertragung der Nachricht an den Relay-Dienst und vom Relay-Dienst. Reise innerhalb der Relay-Dienst ist nicht gesichert.
Dies bedeutet, dass in der Theorie der Relay-Dienst kann, auf die Kommunikation zwischen dem Client und der Dienst abzuhören und sogar die Nachrichten manipulieren. Allerdings glauben ich, dass in der Praxis dies unpraktisch den Umfang des Datenverkehrs, der .NET Services Bus zugewiesen ist. Einfach ausgedrückt, diese Art von Subversion kann nicht als übrigens ausgeführt werden und erfordert dedizierte Ressourcen, Planung, Mitarbeiter und Technologie. Darüber hinaus hat Microsoft im Laufe der Jahre erwiesen, dass die höchste Integrität und Respekt für seine Kunden sindDatenschutz, und es enthält viele andere Bereiche, die es wäre es tatsächlich böswillige missbraucht haben konnte.

Nachrichtensicherheit
Nachrichtensicherheit werden im Hauptteil der Nachricht mit einem Dienst bereitgestellten Zertifikat verschlüsselt. Da die Nachricht selbst statt des Transports geschützt ist, ist die Reise in die Weiterleitung sowie geschützt. Der Nachteil Nachrichtensicherheit ist, dass zusätzliche Einrichtungsschritte erforderlich sind.
Während ich denken, dass im praktischen Transport Sicherheit genug ist, ist es wichtig, um Kunden und Benutzer vom Vorhandensein von End-to-End-Vertraulichkeit und Integrität sicherzustellen und sogar theoretische Kompromisse vorzubeugen. Es empfiehlt sich daher immer abhängig Nachrichtensicherheit für die gesamte weitergeleitete Kommunikation, der außerdem weitere Vorteile, wie die direkte Verbindung und der Verfügbarkeit Sicherheitsaufrufkontext an den Dienst bereitstellt.
Im Gegensatz zu möglicherweise in Transportsicherheit, in der Nachrichtensicherheit die Nachricht die Anmeldeinformationen des Clients enthalten. Der Haupteinsatzzweck von Clientanmeldeinformationen vom Dienst ist für die lokale Autorisierung des Aufrufs an einige rollenbasierte Sicherheitsrichtlinie einrichten. Wenn die Meldung Anmeldeinformationen enthält, muss der Dienst auch diese authentifizieren (selbst wenn er benötigt lediglich den Client autorisiert). Beachten Sie, dass solche Authentifizierung über die Authentifizierung der Relay-Dienst wurde bereits ausgeführt. Wenn der Relay-Dienst den Client bereits authentifiziert hat, den Anruf erneut vom Dienst authentifiziert keine hinzu viel im Weg von Sicherheit, noch Sie burdens den Dienst verwalten die Anmeldeinformationen des Clients. Wenn der Relay-Dienst den Client nicht authentifiziert, gilt der Dienst auf den unerwünschten Datenverkehr nicht authentifizierte Clients die schwere IT Vorgänge Auswirkungen haben, konnte der ASP.NET-Sicherheitsrichtlinie.
Aus diesen Gründen finde ich, dass die optimale Methode für die Relay-Dienst zum Authentifizieren des Clients und vermeiden Sie den Dienst noch einmal auszuführen ist. Sie sollten den Dienst auch entwerfen, so dass es keine Notwendigkeit, die Anmeldeinformationen des Clients. Solche Entwurf wird das Entwurfsmuster der Kette von Vertrauensstellungen ausgerichtet, die auch in einer geschichteten Architektur funktioniert. Andererseits gibt es Fälle, in der Dienst die Anmeldeinformationen des Clients für eine lokale Verwendung außer Autorisierung, z. B. Personalisierung, Überwachung oder proprietäre Integration von Legacysystemen benötigt.

TCP Relay binden und Übertragen der Sicherheit
Die TCP-Relay Bindung Standardeinstellungen zum Transportieren von Sicherheit und keine speziellen Konfigurationsschritte sind erforderlich. Sie verwendet einfach SSL über Anschluss 828. Wenn Sie Transportsicherheit verwenden, können jedoch Sie nur den Verbindungsmodus TCP Relay Bindung von TcpRelayConnectionMode.Relayed verwenden.
Da der Aufruf anonym ist, auf der Dienstseite fügt Windows Communication Foundation (WCF) einen generischen Principal mit einer leeren Identität an den Thread, den Aufruf ausgeführt und die ServiceSecurityContext ist null.
Um die Übertragung der Nachricht zu schützen, müssen Sie Service Host mit einem Zertifikat konfigurieren. Der Client wird standardmäßig aushandeln in das Zertifikat (abgerufen seinen öffentlichen Schlüssel), sodass nicht erforderlich ist, das Zertifikat in der Konfigurationsdatei des Clients explizit auflisten. Allerdings muss der Client weiterhin das ausgehandelte Zertifikat überprüfen. Optimale Vorgehensweise besteht wie bei regulären WCF und Nachrichtensicherheit, überprüft das Zertifikat mit Peer-Vertrauensstellung, d. h. Installieren des Zertifikats im Voraus in den Clientordner vertrauenswürdige Personen. Neben Absicherung true End-to-End-Übertragung über das Relay, ermöglicht das mit Nachrichtensicherheit auch die Verwendung von Verbindungsmodi direkte und Hybrid.
Wie zuvor beschrieben, wird die Nachricht möglicherweise oder enthält möglicherweise nicht die Anmeldeinformationen des Clients. Wenn Sie die Anmeldeinformationen in der Nachricht gesendet vermeiden, wird WCF angefügt, an den Thread Ausführen des Aufrufs einer Windows-principal mit einem leeren Identität nicht viel Sinn macht. Wenn Sie Nachrichtensicherheit ohne Anmeldeinformationen verwenden, sollten Sie auch Host PrincipalPermissionMode auf keine zu den gleichen Principal als mit Transportsicherheit festlegen. Um die Bindung für die Nachrichtensicherheit mit anonyme Aufrufe zu konfigurieren, verwenden Sie MessageCredentialType.None, und die ClientCredentialType-Eigenschaft des MessageSecurityOverRelayConnection, in die Message-Eigenschaft der NetTcpRelaySecurity verfügbar weisen Sie, Wert . Abbildung 8 zeigt Code, der dies veranschaulicht.
public sealed class NetTcpRelaySecurity
{
   public EndToEndSecurityMode Mode 
   {get;set;}
   public MessageSecurityOverRelayConnection Message
   {get;}
   //More members
}
public sealed class MessageSecurityOverRelayConnection
{
   public MessageCredentialType ClientCredentialType
   {get;set;}
   //More members
}
Abbildung 9 zeigt die erforderlichen Host clientseitigen Config-Datei.
  <service name = "..." behaviorConfiguration = "MessageSecurity">
      <endpoint
         ...
         binding  = "netTcpRelayBinding"
         bindingConfiguration = "MessageSecurity"
      />
   </service>
   ...
      <serviceBehaviors>
         <behavior name = "MessageSecurity">
            <serviceCredentials>
               <serviceCertificate
                  findValue     = "MyServiceCert"
                  storeLocation = "LocalMachine"
                  storeName     = "My"
                  x509FindType  = "FindBySubjectName"
               />
            </serviceCredentials>
            <serviceAuthorization principalPermissionMode ="None"/>
         </behavior>
      </serviceBehaviors>
   <bindings>
      <netTcpRelayBinding>
         <binding name = "MessageSecurity">
            <security mode = "Message">
               <message clientCredentialType = "None"/>
            </security>
         </binding>
      </netTcpRelayBinding>
   </bindings>
Auf der Clientseite müssen Sie Name des Zertifikats in die Identität Adresse des Endpunkts einschließen, da diesen Namen nicht die Relaydomäne Dienst übereinstimmt. Abbildung 10 zeigt die erforderlichen Config-Datei.
<client>
   <endpoint behaviorConfiguration = "ServiceCertificate"
      binding  = "netTcpRelayBinding"
      bindingConfiguration = "MessageSecurity"
      <identity>
         <dns value = "MyServiceCert"/>
      </identity>
      ...
   </endpoint>
</client>
<bindings>
   <netTcpRelayBinding>
      <binding name = "MessageSecurity">
         <security mode = "Message">
            <message clientCredentialType = "None"/>
         </security>
      </binding>
   </netTcpRelayBinding>
</bindings>
<behaviors>
   <endpointBehaviors>
      <behavior name = "ServiceCertificate">
         <clientCredentials>
            <serviceCertificate>
               <authentication certificateValidationMode= "PeerTrust"/>
            </serviceCertificate>
         </clientCredentials>
      </behavior>
   </endpointBehaviors>
</behaviors>
Wenn Sie die Anmeldeinformationen des Clients in der Nachricht einschließen möchten, muss der Dienst auch diese Anmeldeinformationen, mit der gleiche Einstellung als mit normalen TCP-Aufrufe authentifizieren. In diesem Fall die Service principal und primäre Identität wird beide über eine Identität entsprechen diese Anmeldeinformationen verfügen. Die Anmeldeinformationen möglich ein Benutzername und Kennwort, ein Zertifikat oder eine ausgestellte Token. Sie müssen die Host sowohl auf dem Client die Bindung der Typen von Anmeldeinformationen, die Sie davon ausgehen, dass, angeben. Verwenden Sie für Namen von Benutzeranmeldeinformationen beispielsweise Folgendes ein:
<bindings>
   <netTcpRelayBinding>
      <binding name = "MessageSecurity">
         <security mode = "Message">
            <message clientCredentialType = "UserName"/>
         </security>
      </binding>
   </netTcpRelayBinding>
</bindings>
Auf der Seite Host Wenn die Anmeldeinformationen Benutzername und Kennwort sind, Sie müssen auch konfigurieren, mit Verhaltensweisen, zum Authentifizieren und Autorisieren die Anmeldeinformationen. Standardmäßig werden Windows-Anmeldeinformationen, aber die häufiger Wahl würden werden verwenden einige Anmeldeinformationsspeicher z. B. die XML-Webdienste Anbieter:
<service name = "..." behaviorConfiguration = "CustomCreds">
   ...
</service>
...
<serviceBehaviors>
   <behavior name = "CustomCreds">
      <serviceCredentials>
         <userNameAuthentication 
            userNamePasswordValidationMode = "MembershipProvider"
         />
      </serviceCredentials>
      <serviceAuthorization principalPermissionMode = "UseAspNetRoles"/>
   </behavior>
</serviceBehaviors>
Der Client hat zum Auffüllen des Proxys mit den Anmeldeinformationen. Wenn Sie einen Benutzernamen und ein Kennwort zu verwenden, würde der Clientcode einfügen wie folgt sein:
MyContractClient proxy = new MyContractClient();
proxy.ClientCredentials.UserName.UserName = "MyUserName";
proxy.ClientCredentials.UserName.Password = "MyPassword";

proxy.MyMethod();

proxy.Close();
Der Client hat keine Möglichkeit bekannt, wenn die Anmeldeinformationen bietet auf der Dienstseite als Windows oder benutzerdefinierte Anmeldeinformationen authentifiziert sind.
Gemischte Übertragungssicherheit ist die einzige Möglichkeit, anonyme Aufrufe über Transportsicherheit zu vermeiden. Da Transportsicherheit Anmeldeinformationen übergeben nicht möglich, übergeben Sie die Anmeldeinformationen mit Nachrichtensicherheit, daher der Begriff gemischt. Wenn die mit gemischten Übertragungssicherheit über die TCP-Weiterleitung binden Sie mit eingeschränkten werden weitergeleitet nur Verbindungen.
Abbildung 11 zeigt, wie der Dienst oder der Client für gemischte Sicherheit konfigurieren.
   <endpoint
      binding  = "netTcpRelayBinding"
      bindingConfiguration = "MixedSecurity"
      ...
   />
...
<bindings>
   <netTcpRelayBinding>
      <binding name = "MixedSecurity">
         <security mode = "TransportWithMessageCredential"/>
      </binding>
   </netTcpRelayBinding>
</bindings>
Nachdem die Nachrichten vom Dienst empfangen werden, muss der Host wie mit normalen TCP die Aufrufe authentifizieren. Nach der Authentifizierung verfügen der Webdienstaufruf ein principal-Objekt entsprechen die bereitgestellten Anmeldeinformationen und eine Sicherheitsaufrufkontext.

Bindung für WS-Relay und Übertragung Sicherheit
Die WS-Bindung mit Transportsicherheit kombinieren ist als einfach wie das Adressschema von HTTP auf HTTPS ändern und Festlegen der Bindung an Transportsicherheit, verwenden Sie wie im Abbildung 12 dargestellt.
   <endpoint
     address  = "https://MySolution.servicebus.windows.net/..."
     binding  = "wsHttpRelayBinding"
     bindingConfiguration = "TransportSecurity"
     ...
   />

<bindings>
   <wsHttpRelayBinding>
      <binding name = "TransportSecurity">
         <security mode = "Transport"/>
      </binding>
   </wsHttpRelayBinding>
</bindings>
Beachten Sie, dass die WS Bindung der Standardwert mit Nachrichtensicherheit für Übertragungssicherheit per Relay weiterleiten. Da Nachrichtensicherheit zusätzliche Konfigurationsschritte erfordert, die WS Bindung relay funktioniert nicht wie - liegt außerhalb des im Feld alle Aufrufe fehl. Allerdings konfigurieren die Bindung an diese Nachricht verwenden WS-Weiterleitung (oder gemischt) Sicherheit ist identisch mit die TCP-Relay-Bindung konfigurieren.

Unidirektionale Datenbindung von Relay und Übertragung Sicherheit
Die unidirektionale Relay-Bindung (und deren Unterklassen) ist der nur Bindung, die standardmäßig auf müssen überhaupt keine Übertragungssicherheit. Darüber hinaus unterstützt es gemischten Übertragungssicherheit nicht. Konfigurieren Transportsicherheit verwenden ist identisch mit den TCP- und WS-Relay-Bindungen. Konfigurieren Nachrichtensicherheit verwenden ähnliche jedoch einen wichtigen Unterschied ist – die unidirektionale Relay-Bindung kann nicht das Dienstzertifikat aushandeln, da auch möglicherweise kein Dienst und keine direkte Interaktion mit dem Dienst stattfindet. Wenn auf dem Client Nachrichtensicherheit verwenden, müssen Sie das Dienstzertifikat explizit angeben, wie in Abbildung 13 dargestellt.
<client>
   <endpoint behaviorConfiguration = "ServiceCertificate"
      ...
   </endpoint>
</client>

<behaviors>
   <endpointBehaviors>
      <behavior name = "ServiceCertificate">
         <clientCredentials>
            <serviceCertificate>
               <scopedCertificates>
                  <add targetUri = "sb://MySolution.servicebus..."
                     findValue     = "MyServiceCert"
                     storeLocation = "LocalMachine"
                     storeName     = "My"
                     x509FindType  = "FindBySubjectName"                        
                  />
               </scopedCertificates>
            </serviceCertificate>
         </clientCredentials>
      </behavior>
   </endpointBehaviors>
</behaviors>
Ein anderer wichtiger Unterschied zwischen unidirektionale Relay Bindung und der andere Relay-Bindungen hat ist der Aufruf anonyme, mit der Transport- oder Nachricht Sicherheit, der Aufruf ein Sicherheitsaufrufkontext, deren primäre Identität ist
service bus certificate CN=servicebus.windows.net. 

Vereinfachen der Transfer Sicherheit
Während der Übertragungssicherheit eine Fülle von Details und komplizierte Optionen bietet, sollten können und optimieren und automatisieren die meisten dieser Sicherheitsentscheidungen für die Konfiguration. Verwenden Sie auf der Seite Host zu kapseln, Meine ServiceBusHost-Klasse, definiert als die folgenden einfügen:
public class ServiceBusHost : ServiceHost
{
   public ServiceBusHost(object singletonInstance, params Uri[] baseAddresses);
   public ServiceBusHost(Type serviceType,params Uri[] baseAddresses);

   public void ConfigureAnonymousMessageSecurity(string serviceCert);
   public void ConfigureAnonymousMessageSecurity(string serviceCert,
                            StoreLocation location,StoreName storeName);
   public void ConfigureAnonymousMessageSecurity(StoreLocation location,
            StoreName storeName,X509FindType findType,object findValue);

   //More members
}
Wenn ServiceBusHost verwenden, ist keine andere Einstellung in der Konfigurationsdatei oder in Code erforderlich. Die ConfigureAnonymousMessageSecurity-Methode können Sie pro Meine Empfehlung um anonyme Aufrufe über Nachrichtensicherheit zu aktivieren. Müssen Sie es bereitstellen ist der Zertifikat verwenden:
ServiceBusHost host = new ServiceBusHost(typeof(MyService));
host.ConfigureAnonymousMessageSecurity("MyServiceCert");
host.Open();
ConfigureAnonymousMessageSecurity wird standardmäßig, den Zertifikat-Speicherort auf dem lokalen Computer und den gewünschten Zertifikatspeicher My, und es wird das Zertifikat anhand seines allgemeinen Namens nachschlagen. Wenn Sie ConfigureAnonymousMessageSecurity nicht aufrufen, wird ServiceBusHost der Projektmappenname für den Zertifikatnamen mit anonymen Nachrichtensicherheit standardmäßig:
ServiceBusHost host = new ServiceBusHost(typeof(MyService));
host.Open();
Sie können auch die überladenen Versionen verwenden, mit die Sie einige oder alle Details der Zertifikat explizit festlegen können.
ServiceBusHost nutzt die ConfigureBinding-Methode des ServiceBusHelper. ConfigureBinding standardmäßig anonyme Aufrufe. Wenn die Aufrufe über Anmeldeinformationen verfügen, verwendet die ConfigureBinding immer Username-Anmeldeinformationen. Die TCP-Relay-Bindung verwendet ConfigureBinding den Hybrid-Verbindungsmodus. ConfigureBinding kann ebenfalls immer zuverlässige Nachrichten.
ServiceBusHost unterstützt außerdem die Nachrichtensicherheit mit Anmeldeinformationen über die ConfigureMessageSecurity-Methoden:
public class ServiceBusHost : ServiceHost
{
   public void ConfigureMessageSecurity();
   public void ConfigureMessageSecurity(string serviceCert);
   public void ConfigureMessageSecurity(string serviceCert,
                                        string applicationName);
   public void ConfigureMessageSecurity(string serviceCert,
                                        bool useProviders,
                                        string applicationName);
   //More members
}
ConfigureMessageSecurity standardmäßig mithilfe der XML-Webdienste Mitgliedschaftsanbieter, aber es kann angewiesen, sowie Windows-Benutzerkonten zu verwenden. Die Implementierung der ConfigureMessageSecurity ähnelt der ConfigureAnonymousMessageSecurity.
Sie können eine einfache Möglichkeit, konfigurieren Nachrichtensicherheit mit Meine ServiceBusClientBase < T >, definiert als Clients bereitstellen.
public abstract class ServiceBusClientBase<T> : ClientBase<T> where T : class
{
   public ServiceBusClientBase();
   public ServiceBusClientBase(string endpointName);
   public ServiceBusClientBase(Binding binding,
                               EndpointAddress remoteAddress);
   public ServiceBusClientBase(string username,string password);

   public ServiceBusClientBase(string endpointName,
                               string username,string password);
   public ServiceBusClientBase(Binding binding,EndpointAddress address,
                               string username,string password);

   protected virtual void ConfigureForServiceBus();
   protected virtual void ConfigureForServiceBus(string username, string password);

}
ServiceBusClientBase < T >bietet zwei Sätze von Konstruktoren. Die Konstruktoren, die lediglich die Endpunkt-Parameter alle, annehmen anonyme Aufrufe mit Nachrichtensicherheit. Sie können auch die Konstruktoren verwenden, die Anmeldeinformationen die Benutzername und das Kennwort zu akzeptieren. Wenn kein Endpunkt Identität ist ServiceBusClientBase < T > bereitgestelltstandardmäßig den Namen der Projektmappe. Verwenden Sie ServiceBusClientBase < T >wie der WCF bereitgestellte ClientBase < T >:
[ServiceContract]
interface IMyContract
{
   [OperationContract]
   void MyMethod();
}
class MyContractClient : ServiceBusClientBase<IMyContract>,IMyContract
{
   public MyContractClient()
   {}
   public void MyMethod()
   {
      Channel.MyMethod();
   }
}
Der Beispiel-Code-Download enthält die vollständige Implementierung der ServiceBusClientBase < T >. ServiceBusClientBase < T >verwendet Peer-Vertrauensstellung, um das Dienstzertifikat zu überprüfen. Der Großteil der Arbeit erfolgt durch die Bindung Endpunkt an ServiceBusHelper.ConfigureBinding übergeben.
Der eine verbleibende Nachteile Punkt ist die Bindung unidirektionale Relay mit seine mangelnde Zertifikatsverhandlung. Zu verringern, habe ich OneWayClientBase < T > geschrieben:
public abstract class OneWayClientBase<T> : ServiceBusClientBase<T>   where T : class
{
   //Same constructors as ServiceBusClientBase<T> 

   public void SetServiceCertificate(string serviceCert);
   public void SetServiceCertificate(string serviceCert,
                                     StoreLocation location,
                                     StoreName storeName);
   public void SetServiceCertificate(object findValue,
        StoreLocation location,StoreName storeName,X509FindType findType);
}
OneWayClientBase < T >wird von ServiceBusClientBase < T > abgeleitetund fügt die SetServiceCertificate-Methoden. Wenn Sie nie, SetServiceCertificate aufrufen, OneWayClientBase < T >einfach sucht das Dienstzertifikat aus Config. SetServiceCertificate bietet eine einfache programmgesteuerte Möglichkeit die Konfigurationsdatei ganz vermeiden. Er legt auch das Tag Identität die Endpunktadresse. SetServiceCertificate verwendet dieselben Standardwerte wie ServiceBusHost, einschließlich der Verwendung der Projektmappenname für den Zertifikatnamen, wenn kein Zertifikat bereitgestellt wird. Hier ist die Verwendung von OneWayClientBase < T >:
class MyContractClient : OneWayClientBase<IMyContract>,IMyContract
{
   public MyContractClient() 
   {}
   public void MyMethod()
   {
      Channel.MyMethod();
   }
}

MyContractClient proxy = new MyContractClient();
proxy.SetServiceCertificate("MyServiceCert");

proxy.MyMethod();

proxy.Close();
Wie Sie sehen können, mithilfe von OneWayClientBase < T >ist einfach.

Senden Sie Ihre Fragen und Kommentare zu mmnet30@microsoft.com.

Juval Lowy Architekt eine Software mit IDesign WCF-Schulungen und Beratung Architektur bereitstellen. Sein aktuelle Buch ist Programming WCF Services 2nd Edition (O' Reilly, 2008). Er ist auch die Microsoft Regional Director für Silicon Valley. Erreichen Sie Juval unter www.idesign.net.

Page view tracker