I'm writing a small WCF service and I'd like to be able to write to a custom event log. I've created an event log and source and a minimal service and the service can write to the log. Then I added impersonation and started getting 'Access is denied' errors at the client. When logged at the server, it takes the form of a 'Requested registry access is not allowed' error.
Although this wouldn't be the case with users of the service, the account being impersonated is (necessarily) a member of Administrators (in order to be able to debug using IIS).
I get the same results running the WCF Test Client on the same machine with a non-admin user, and on another machine with a non-admin user.
To recreate:
- Start PowerShell as Administrator
- New-EventLog -LogName Test42 -Source Test42.Web
- Close PowerShell
- Start Visual Studio as Administrator
- New Project - .NET Framework 4.5 > Visual C# > WCF > WCF Service Application 'ImpSvc1' (* Create directory for solution)
- Replace the contents of IService1.cs, Service1.svc and Web.config with the contents below.
- In the WCF Project Properties > Web (tab) > Servers - choose Local IIS and click Create Virtual Directory.
- Build the Project.
- Start IIS Manager - Select the Default Web Site
- Open IIS
- You'll need an Application Pool with a domain account (with no special permissions on the IIS machine) and integrated pipeline mode, so create one if you haven't got one.
- Select Default Web Site > Authentication. Ensure Windows Authentication is enabled and all others are disabled.
- Select ImpSvc1 > Basic Settings. Select the Application pool from above.
- Close IIS Manager.
- Start the WCF Test Client. File > Add Service > http://localhost/ImpSvc1/Service1.svc
- Double-click on the GetDate() method and click Invoke. You should get RESPONSE: user=; dateTime= and en event created in the Test42 event log.
- Uncomment the using statement, build and repeat the Invoke and you should get: RESPONSE: user=; dateTime= and en event created in the Test42 event log.
- Uncomment the EventLog.WriteEntry statement, build and repeat the Invoke and you should get an 'Access is denied' error in the WCF Test Client.
- If you start the project with Debugging, you'll see it's a 'Requested registry access is not allowed.'
IService1.cs
using System;
using System.ServiceModel;
namespace ImpSvc1
{
[ServiceContract]
public interface IService1
{
[OperationContract]
String GetData();
}
}
Service1.svc
using System;
using System.Diagnostics;
using System.Security.Principal;
using System.ServiceModel;
namespace ImpSvc1
{
public class Service1 : IService1
{
public String GetData()
{
EventLog.WriteEntry("Test42.Web", "Test message",
EventLogEntryType.Information, 1, 0);
//using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
//{
//EventLog.WriteEntry("Test42.Web", "Test message from using statement",
// EventLogEntryType.Information, 2, 0);
return String.Format("RESPONSE: user={0}; dateTime={1}",
WindowsIdentity.GetCurrent().Name, DateTime.Now);
//}
}
}
}
Web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext"
value="true" />
</appSettings>
<system.web>
<compilation debug="true"
targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding closeTimeout="00:05:00"
openTimeout="00:05:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"
httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpBinding"
scheme="http" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
<security>
<authentication>
<anonymousAuthentication enabled="false" />
<windowsAuthentication enabled="true" />
</authentication>
</security>
</system.webServer>
</configuration>