WCF Windows Authentication - How to?

  • Thread starter Thread starter vpabloortiz
  • Start date Start date
V

vpabloortiz

Hi everyone,

I have a simple requirement to create a web service and be able to
determine the identities of clients connecting to it (ie. if I'm
logged in as Me@domain and I call some method on the service, the
service should be able to grab this info and perform some custom
authentication, perhaps look up "Me@domain" in a database table). The
problem I'm having is that when I debug a call on the service and look
at the Thread.CurrentThread's identity information, all I see is the
NETWORK SERVICE account name rather than the identity of the caller.
It was my impression that the calls would be serviced under the
context of the calling client, so I must have something set up wrong.
Can anyone lend a hand? This is what I've done :

WCF SERVICE
===========
1) In the constructor I execute the following line of code :

AppDomain.CurrentDomain.SetPrincipalPolicy
(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);

2) In the Web.config, I've set the binding to netTcpbinding which uses
transport level security and Windows Auth by default

<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="MyServiceBehavior"
name="MyOwnService.MyOwnService">
<endpoint address="" binding="netTcpBinding"
bindingConfiguration="MyTestBinding"
contract="MyOwnService.IMyOwnService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:49910/MyOwnService/" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="MyTestBinding" />
</netTcpBinding>
</bindings>

<behaviors>
<serviceBehaviors>
<serviceDebug
includeExceptionDetailInFaults="True"/>
<dataContractSerializer
maxItemsInObjectGraph="2147483647" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration>

WINDOWS SERVICE
================
Since I'm using netTcpBinding, I can't host it in IIS versions < 7.0,
so I chose to host it in a windows service, which I've set up to run
under the NETWORK SERVICE account.

CLIENT
=====
The client's app.config is generated via svcutil, and is as follows :

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_MyOwnService"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00"
transactionFlow="false"
transferMode="Buffered" transactionProtocol="OleTransactions"

hostNameComparisonMode="StrongWildcard" listenBacklog="10"
maxBufferPoolSize="10524288"
maxReceivedMessageSize="2147483647" maxConnections="10"<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<reliableSession ordered="true"
inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport
clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message
clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:49910/
MyOwnService/"
binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_MyOwnService"
contract="MyOwnServiceReference.MyOwnService"
name="NetTcpBinding_MyOwnService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
 
Anyone at all? No security gurus out there?

Hi everyone,

I have a simple requirement to create a web service and be able to
determine the identities of clients connecting to it (ie. if I'm
logged in as Me@domain and I call some method on the service, the
service should be able to grab this info and perform some custom
authentication, perhaps look up "Me@domain" in a database table). The
problem I'm having is that when I debug a call on the service and look
at the Thread.CurrentThread's identity information, all I see is the
NETWORK SERVICE account name rather than the identity of the caller.
It was my impression that the calls would be serviced under the
context of the calling client, so I must have something set up wrong.
Can anyone lend a hand? This is what I've done :

WCF SERVICE
===========
1) In the constructor I execute the following line of code :

AppDomain.CurrentDomain.SetPrincipalPolicy
(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);

2) In the Web.config, I've set the binding to netTcpbinding which uses
transport level security and Windows Auth by default

<?xml version="1.0"?>
<configuration>
      <system.serviceModel>
            <services>
   <service behaviorConfiguration="MyServiceBehavior"
name="MyOwnService.MyOwnService">
    <endpoint address="" binding="netTcpBinding"
bindingConfiguration="MyTestBinding"
     contract="MyOwnService.IMyOwnService">
     <identity>
      <dns value="localhost" />
     </identity>
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding"
contract="IMetadataExchange" />
    <host>
     <baseAddresses>
      <add baseAddress="net.tcp://localhost:49910/MyOwnService/" />
     </baseAddresses>
    </host>
   </service>
  </services>
            <bindings>
                  <netTcpBinding>
                        <binding name="MyTestBinding" />
                  </netTcpBinding>
            </bindings>

            <behaviors>
                  <serviceBehaviors>
                        <behavior name="MyServiceBehavior">
                              <serviceMetadata httpGetEnabled="false"/

                              <serviceDebug
includeExceptionDetailInFaults="True"/>
                              <dataContractSerializer
maxItemsInObjectGraph="2147483647" />
                        </behavior>
                  </serviceBehaviors>
            </behaviors>
      </system.serviceModel>
      <system.web>
            <compilation debug="true"/>
      </system.web>
</configuration>

WINDOWS SERVICE
================
Since I'm using netTcpBinding, I can't host it in IIS versions < 7.0,
so I chose to host it in a windows service, which I've set up to run
under the NETWORK SERVICE account.

CLIENT
=====
The client's app.config is generated via svcutil, and is as follows :

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.serviceModel>
        <bindings>
                    <netTcpBinding>
                          <binding name="NetTcpBinding_MyOwnService"
closeTimeout="00:01:00"
                                    openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00"
                                    transactionFlow="false"
transferMode="Buffered" transactionProtocol="OleTransactions"

hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                                    maxBufferPoolSize="10524288"
maxReceivedMessageSize="2147483647" maxConnections="10"
                    >
                                <readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647" maxArrayLength="2147483647"
                                          maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
                                <reliableSession ordered="true"
inactivityTimeout="00:10:00"
                                           enabled="false" />
                                <securitymode="Transport">
                                      <transport
clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                                      <message
clientCredentialType="Windows" />
                                </security>
                          </binding>
                    </netTcpBinding>
              </bindings>
        <client>
            <endpoint address="net.tcp://localhost:49910/
MyOwnService/"
                binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_MyOwnService"
                contract="MyOwnServiceReference.MyOwnService"
name="NetTcpBinding_MyOwnService">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>
 
Hi,

You need to enable message-level security negotiation. Then you can set the
remote user's credentials on the client and get them on the server from the
context, not as you attempt - from the current thread.

Try looking up message level security to see examples and explanations.

Hope this helps
Martin Dechev
 
Hi Martin,

Do I really have to enable message level security? I thought transport
level security would be sufficient for my case. In a nutshell, all I
want is the ability for a windows client (on a domain) to connect to
my service and for my service to be able to fetch its account name
(eg. "SomeClient@SomeDomain") via windows authentication.

Regards,

Anthony
 
OperationContext.Current.ServiceSecurityContext.WindowsIdentity

This is the way to retrieve the WindowsIdentity object (describing the caller's identity) when you're on the server side inside a service method implementation.

Clique.
 
Back
Top