views:

4442

answers:

8

I have a WCF service, hosted in IIS 7.0 that needs to run database queries. In order to get the right permissions to do this I am impersonating within the service as follows:

Code

[OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
public void MyOperation(int arg)

Configuration

<behavior name="ReceivingServiceBehavior">
    <!-- Other behaviors -->
    <serviceAuthorization impersonateCallerForAllOperations="true" />
</behavior>

When I try to connect and run my query I get the following:

Exception - System.IO.FileLoadException: Could not load file or
assembly 'System.Transactions, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089' or one of its dependencies. Either a
required impersonation level was not provided, or the provided
impersonation level is invalid. (Exception from HRESULT: 0x80070542)

File name: 'System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' ---> System.Runtime.InteropServices.COMException (0x80070542): Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542)
   at System.Data.Linq.SqlClient.SqlConnectionManager.UseConnection(IConnectionUser user)
   at System.Data.Linq.SqlClient.SqlProvider.get_IsSqlCe()
   at System.Data.Linq.SqlClient.SqlProvider.InitializeProviderMode()
   at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
   at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable.GetEnumerator()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Fourth.GHS.MessageRelay.RegistrationDBStorage.FindRegistration(SystemKey key)
A: 

Hmmm... I don't know. However, you could force the dll to load early on. Since you are using IIS, this would presumably be in your global.asax - something like creating and throwing away a TransactionScope should do the job...

Marc Gravell
+2  A: 

If you want the SQL queries to be executed as the impersonated identity, you may actually need to enable delegation to your SQL server. Check out this article for more info:

http://msdn.microsoft.com/en-us/library/ms730088.aspx

MattK
I've got our admin to enable delegation and that seemed to do the trick for the service. However, that service calls another backend service and the delegation is falling over there now.
Simon
Are you running into issues with DTC? You may need to look into enabling it if you are having the transaction cross to another machine past the service. As far as credentials, are you using the Windowsidentity.Impersonate method to impersonate as you call the other service?
MattK
A: 

Having played around with this some more, the easiest solution for IIS hosted services is to run your Application Pool with the identity of a domain user that has the requisite permissions. There are probably issues with this in terms of security but for our purposes it's good enough. We can restrict the permissions given to that user but everything works without having to get into Kerberos, impersonation, delegation and the mysteries of AD.

Simon
+2  A: 

Does your WCF client set the required "allowed impersonation level":

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>

        <!-- .... -->

        <behaviors>
           <endpointBehaviors>
              <behavior name="ImpersonationBehavior">
                 <clientCredentials>
                      <windows allowedImpersonationLevel="Impersonation" />
                 </clientCredentials>
              </behavior>
           </endpointBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

By default this is set to Identification if nothing is specified explicitly. Check out this blog post for more info.

huseyint
A: 

Hi , I have the same problem when I'm loadind an XML file to my project . I get the exception : System.IO.File.ReadAllText(pXmlFile) Run-time exception thrown : System.IO.IOException - Either a required impersonation level was not provided, or the provided impersonation level is invalid.

someone has any idea what should I define in the configuration file in order to prevent this exception? thanks, Liron .

A: 

thank you guys, I solved it by reading the XML under the declaration of : _ it worked only when I read the XML directly from the WCFService Class.

Liron Prihar.

A: 

the decleration : [OperationBehavior(Impersonation:=ImpersonationOption.Required)]

in the WCF service class.

A: 

Thank you huseyint. I've been fighting this one for the past day and a half. Here's some stuff that would have saved me a ton of time. So hopefully it will save someone else some time. I was having problems with the SQLConnection and impersonation throwing a registry access is denied using transport security. I tried even using transportwithmessagecredential. Inside of procmon I was getting "Bad Impersonation". My config is IIS 7, virtual dir only has windows authentication enabled and I disabled kernel mode authentication. Basic settings I set it to use pass through authentication.

Service Config -

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
    <services>
      <service behaviorConfiguration="SymitarService.ScheduleServiceBehavior" name="SymitarService.ScheduleService">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsSecure" contract="SymitarService.IScheduleService">
          <identity>
            <dns value="localhost" />            
          </identity>
        </endpoint>
        <endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsSecure" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SymitarService.UserDirectoryBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceAuthorization impersonateCallerForAllOperations="true" />
        </behavior>
        <behavior name="SymitarService.ScheduleServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceAuthorization impersonateCallerForAllOperations="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="tcpSecure" portSharingEnabled="true" />
      </netTcpBinding>
      <wsHttpBinding>
        <binding name="wsSecure" allowCookies="true">
          <security mode="Transport">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
            <message clientCredentialType="Windows" negotiateServiceCredential="true" />
          </security>
        </binding>
      </wsHttpBinding>
      <mexTcpBinding>
        <binding name="mexSecure" />
      </mexTcpBinding>
    </bindings>
  </system.serviceModel>

and the client

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IScheduleService" closeTimeout="01:00:00" openTimeout="01:00:00" receiveTimeout="01:00:00" sendTimeout="01:00:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" useDefaultWebProxy="true" allowCookies="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:20:00" enabled="false" />
          <security mode="Transport">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" realm="" />
            <message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ImpersonationBehavior">
          <clientCredentials>
            <windows allowedImpersonationLevel="Impersonation" allowNtlm="true"/>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <client>
      <endpoint address="https://server:444/SymitarService/ScheduleService.svc" 
                binding="wsHttpBinding" 
                bindingConfiguration="WSHttpBinding_IScheduleService" 
                contract="Symitar.ScheduleService.IScheduleService" 
                name="WSHttpBinding_IScheduleService"
                behaviorConfiguration="ImpersonationBehavior"
                >
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>