WCF Impersonation - Specifying Windows Authentication Credentials on the Service Host Side of the WCF Equation

We don't want to use AspNetCompatibility mode in case we ever want to take advantage of net.tcp or another custom binding, so is there a way to specify and implement impersonation (read: userName=,password=) on the WCF Service Host side? Did Microsoft in their infinite wisdom leave this out? 

I posed this question to my friend Dru today after we were having trouble finding a way to do it.  So there are plenty of articles on WCF Impersonation out there, but nearly all of them originate from the client side.  I want to originate my credentials from the service host side.  Why would you want to do that (you ask)? What if I don't want my client to pass me the credentials for my database (and I want to use windows authentication)?  The scenario is that we handle our application accounts at the domain level per environment. The username/password changes in every environment (Development/Test/QA/Production) so hardcoding the username/password in the service host source code is both bad design and no good (we don't even know what the passwords are in QA and Prod). 

Everywhere I look talks about how you most likely want to use compatibility for session state and/or that it is bad because it is less efficient and should only be used for migration purposes.

 

The Temporary (hopefully!) Solution

The only way we have found to do that so far is to turn on aspNetCompatibilityEnabled = “true” in the under system.serviceModel, add the identity to the system.web section in the config file, add your identity tag, and then add the AspNetCompatibilityRequirementsMode attribute to the top of the class.

 

Wenlong has a fantastic posting about Asp.Net Compatibility.

 

Web.config code:

<system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        <services>
            <service name="Organization.Services.TempService" behaviorConfiguration="wsServiceBehavior">
                <endpoint contract="Organization.Contracts.ITempServices"
                          binding="wsHttpBinding"
                          name="TempServiceEndpoint" />
            </service>
        </services>

        <behaviors>
            <serviceBehaviors >
                <behavior name="wsServiceBehavior" >
                    <!-- Before deployment, you should remove the serviceDebug behavior to avoid disclosing information in exception messages -->
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceMetadata httpGetEnabled="true" />
                    <dataContractSerializer maxItemsInObjectGraph="100000" />
                </behavior>
            </serviceBehaviors>

        </behaviors>
        <bindings>

            <wsHttpBinding>
                <binding name="TempService_wsHttpBinding" >
                    <security mode="None"  />
                </binding>
            </wsHttpBinding>
        </bindings>
    </system.serviceModel>
    <system.web>
        <authorization>
            <allow users="?"/>
        </authorization>
        <identity impersonate="true" userName="me" password="you" />
        <authentication mode="Windows"/>
    </system.web>

 

Service Implementation Class:

Imports Organization.Contracts
Imports System.Collections.Generic
Imports System.ServiceModel
Imports System.ServiceModel.Activation

<ServiceBehavior(), AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Required)> _
Public Class TempService : Implements ITempServices

...

End Class

 

 

You can set RequirementsMode to AspNetCompatibilityRequirementsMode.Allowed and it will still work fine.  The default is NotAllowed, which will cause errors.

Other References: http://msdn2.microsoft.com/en-us/library/aa702682.aspx

Twitter