Getting WindowsIdentity in my WCF Web Service

Gary the Llama picture Gary the Llama · Jun 8, 2011 · Viewed 10.1k times · Source

I took over code from a developer that is no longer with us. It's a WCF web service that was originally using a passed in username, but we need it to use the WindowsIdentity instead.

string identity = ServiceSecurityContext.Current.WindowsIdentity.Name;

That code ends up returning an empty string. I'm using a secure (wsHttpSecure) binding so ServiceSecurityContext.Current isn't null or anything. I've been searching for a solution for a day and haven't found anything yet.

Because I'm new to WCF I'm not sure what other information will be relevant. Here are the enabled authentication settings for the web service in IIS:

Anonymous Authentication - Enabled
Windows Authentication - Enabled

And here's the web.config for the web service:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <connectionStrings>
        <clear />
        <add name="LocalSqlServer" connectionString="Data Source=.\instanceNameHere;Initial Catalog=default;Integrated Security=SSPI;"/>
    </connectionStrings>
    <appSettings configSource="appSettings.config" />
    <system.diagnostics>
        <sources>
            <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
                <listeners>
                    <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\ServiceLogs\WebServiceLog.svclog" />
                </listeners>
            </source>
        </sources>
    </system.diagnostics>
    <system.web>
        <trace enabled="true" />
        <membership defaultProvider="XIMembershipProvider" userIsOnlineTimeWindow="30">
            <providers>
                <clear/>
                <add name="XIMembershipProvider" type="LolSoftware.MiddleTier.BusinessLogic.XIMembershipProvider"
      applicationName="LolWebService"/>
            </providers>
        </membership>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
    <system.serviceModel>
        <client />
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
        <behaviors configSource="behaviors.config" />
        <bindings configSource="bindings.config" />
        <services configSource="services.config" />
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
        <handlers>
            <remove name="svc-ISAPI-4.0_64bit"/>
            <remove name="svc-ISAPI-4.0"/>
            <remove name="svc-Integrated-4.0"/>
            <add name="svc-ISAPI-4.0_64bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%systemroot%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
            <add name="svc-ISAPI-4.0" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%systemroot%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
            <add name="svc-Integrated-4.0" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" resourceType="Unspecified" preCondition="integratedMode" />
        </handlers>
    </system.webServer>
</configuration>

As well as bindings.config:

<bindings>
    <wsHttpBinding>
    <binding name="wsHttpSecure">
        <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None" />
            <message clientCredentialType="UserName" />
        </security>
    </binding>
    <binding name="wsHttp">
        <security mode="None" />
    </binding>
   </wsHttpBinding>
</bindings>

Behaviors.config:

<behaviors>
    <serviceBehaviors>
        <behavior name="serviceBehavior">
            <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
            <serviceDebug includeExceptionDetailInFaults="true" />
            <serviceThrottling maxConcurrentCalls="200" maxConcurrentSessions="200" />
            <serviceCredentials>
                <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="XIMembershipProvider"/>
            </serviceCredentials>
        </behavior>
    </serviceBehaviors>
    <!-- -->
    <endpointBehaviors>
        <behavior name="restBehavior">
            <webHttp/>
        </behavior>
    </endpointBehaviors>
    <!-- -->
</behaviors>

Service.config:

<services>
    <service name="LolSoftware.MiddleTier.WebService.LolWebService" behaviorConfiguration="serviceBehavior">
        <endpoint name="LolWebService_WSHttpEndpointSecure" contract="LolSoftware.MiddleTier.Interfaces.ILolWebService" binding="wsHttpBinding" bindingConfiguration="wsHttpSecure"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    </service>
</services>

Thanks in advance.

Answer

Ladislav Mrnka picture Ladislav Mrnka · Jun 8, 2011

If you want to get WindowsIdentity on the service you must use Windows authentication instead of UserName authentication. Be aware that Windows authentication works only for windows accounts in your domain. You should change your IIS configuration and disable anonymous access. Then change wsHttpBinding configuration to:

<bindings>
    <wsHttpBinding>
        <binding name="wsHttpSecure">
            <security mode="Transport">
                <transport clientCredentialType="Windows" />
            </security>
        </binding>
   </wsHttpBinding>
</bindings>

You don't need ASP.NET compatibility to use Windows authentication.