Wednesday, June 24, 2009

Service principal name when using WCF, net.tcp binding, and a domain service account

Service Principal Names (SPN) allow you to assign a name to a service and it will be used as a simple authentication mechanism. Basically, when the client connects to the service, the service sends the client it's SPN. The client also knows what SPN it expects. If they match, things are good.

In order to use the WCF NetTcpBinding with a Windows Service, it is necessary to create a SPN.

Here's the scenario:

We have a Windows Service that exposes a WCF NetTcpBinding service. The Windows service runs as a domain user account instead of LOCAL SYSTEM, NETWORK SERVICE, etc. Let's say the service is running under the account MyDomain\MyServiceAccount.

We have a client on the domain that will access the WCF service.

The problem arises when the client tries to talk to the server. Without an SPN, there is no way for the client to verify it has reached the appropriate service.

So, how do you use an SPN...

  1. We need to create an SPN and associate it with the service account. This is done using a utility called setspn.exe that is located in the Windows 2003 Support Tools.
  2. We need to create the SPN. An SPN consists of two parts, service and host. The format is \. In our case, the host really doesn't matter because we will attach the SPN to a username, not a computer. Here's the command:
    setspn -A MyServiceClass\MyHostName MyDomain\MyServiceAccount
  3. Next, on the client, we need to specify the SPN when we create an endpoint mapping. This can be done using the app.config file or programmatically. In the app.config file, in the section, add

    <identity>
       <serviceprincipalname value="MyServiceClass\MyHostName"/>
    </identity>

    Or we create the endpoint with the SPN..

    EndpointIdentity id = EndpointIdentity.CreateSpnIdentity("MyServiceClass\MyHostName");
    EndpointAddress addr = new EndpointAddress(new Uri(URI), id);




That's it. Now your client will be able to verify the service it is connecting to.

9 comments:

  1. Thanks for this awesome post. Nicely explained the topic and very helpful for beginners.
    Please continue writing.

    Regards:-Offshore software development company

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Kevin, may be you know.
    If domain user account have more than one SPN records associated with itself which record WCF will be use?
    We have custom WIF STS. It's not supported explicity configuration of identity by app.config or manual.

    ReplyDelete
    Replies
    1. Wow, I am not sure I have an answer for that one.

      Delete
  4. Hi

    What exactly is the "MyServiceClass" used in the SPN?

    Is it ;
    1. the name of the self hosted process hosting the service?
    2. the virtual address of the service - net.tcp://localhost:9600/MyServiceClass.svc
    3. The actual service class of the wcf service?

    Thank you

    ReplyDelete
    Replies
    1. Hi Wayne, Sorry my post isn't perfectly clear. The Service Class actually has nothing to do with the code, but instead specifies the service group that you are creating. Say you are creating a service for Acme Chat. The service name would could be something like "AcmeChat" and the Hostname indicated the specific machine that service is running on. More well known service classes could be things like "www", "print", "IM", etc. It basically is you coming up with a unique name for the service you are providing ACROSS all computers. Then the host part is used to distinguish if your client is connecting to AcmeService on HostA or HostB.

      I often times just name this after my application. It doesn't have to match anything in your code, your executable name, or anything. It is merely a unique place holder. Think of it like the protocol in URIs (http, https, smtp, etc). Hope that helps!

      Delete
  5. Thank you for sharing such a great info. it will be very helpful for us.
    Offshore Software Development Services
    Offshore Web Development

    ReplyDelete