Posts Tagged ‘WCF’
HOW TO propagate WCF Impersonation to COM objects
I was working on a project to write a wrapper on a COM component in WCF. The COM object needs impersonation in some levels to provide certain functionalities to impersonated user. Basically impersonation in .Net application doesn’t propagate COM calls. I’ve seen following sentence in How To: Use Impersonation and Delegation in ASP.NET 2.0
The impersonation token does not propagate across threads if you use COM interop with components that have incompatible threading models, or if you use unmanaged techniques to create new threads
Actually I have a COM component and I want to use this component in my WCF Services. One of classes in COM object has got a property which returns current user. I wrote a console application to test impersonation and see if impersonation does propagate to COM object or not. I wrote a class for impersonation and it has a method called “ImpersonateUser” that impersonates to passed username and password. Following code returns different username for .net and COM object. It means it doesn’t propagate to COM object.
static void Main(string[] args)
{
DoWork();
Console.ReadLine();
}
private static void DoWork()
{
ImpersonateClass impersonate = new ImpersonateClass();
using (impersonate.ImpersonateUser("AnotherUser",
"Domain",
"passw0rd"))
{
COMTESTLib.TestClass obj = new COMTESTLib.TestClass();
Console.WriteLine(string.Format("COM:{0} .Net:{1}", obj.CurrentUserName,
System.Security.Principal.WindowsIdentity.GetCurrent().Name));
}
}
//Returns:COM:DOMAIN\CurrentUser .Net:DOMAIN\AnotherUser</pre>
But I used CoInitializeSecurity to initialize security with impersonation and cloaking. CoInitializeSecurity should be called before any marshalling so I called CoInitializeSecurity as first function call.
[DllImport("ole32.dll")]
public static extern int CoInitializeSecurity(IntPtr pVoid, int
cAuthSvc, IntPtr asAuthSvc, IntPtr pReserved1, RpcAuthnLevel level,
RpcImpLevel impers, IntPtr pAuthList, int dwCapabilities, IntPtr
pReserved3);
static void Main(string[] args)
{
int result = CoInitializeSecurity(IntPtr.Zero, -1,
IntPtr.Zero, IntPtr.Zero,
RpcAuthnLevel.Connect, RpcImpLevel.Impersonate,
IntPtr.Zero, Convert.ToInt32(EoAuthnCap.DynamicCloaking), IntPtr.Zero);
DoWork();
Console.ReadLine();
}
private static void DoWork()
{
ImpersonateClass impersonate = new ImpersonateClass();
using (impersonate.ImpersonateUser("AnotherUser",
"domain",
"passw0rd"))
{
COMTESTLib.TestClass obj = new COMTESTLib.TestClass();
Console.WriteLine(string.Format("COM:{0} .Net:{1}", obj.CurrentUserName,
System.Security.Principal.WindowsIdentity.GetCurrent().Name));
}
}
//Returns:COM:DOMAIN\AnotherUser .Net:DOMAIN\AnotherUser</pre>
Somebody suggested using built-in impersonation method for WCF so I changed my service to following code by setting [OperationBehavior(Impersonation = ImpersonationOption.Required)] and some changes in Web.Congif to make it work.
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetUserNames()
{
return DoWork();
}
private string DoWork()
{
string result;
COMTESTLib.TestClass obj = new COMTESTLib.TestClass();
result = string.Format("COM:{0} .Net:{1}", obj.CurrentUserName,
System.Security.Principal.WindowsIdentity.GetCurrent().Name);
return result;
}
I passed user credentials from client for impersonation.
static void Main(string[] args)
{
ServiceReference.ServiceImpersonateClient client = new ServiceReference.ServiceImpersonateClient();
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
client.ClientCredentials.Windows.ClientCredential.Domain = "Domain";
client.ClientCredentials.Windows.ClientCredential.UserName = "AnotherUser";
client.ClientCredentials.Windows.ClientCredential.Password = "Passw0rd";
string str = client.GetUserNames();
Console.WriteLine(str);
Console.ReadLine();
client.Close();
}
// Returns COM:DOMAIN\CurrentUser .Net:DOMAIN\AnotherUser
But it returns different usernames which means impersonation of WCF does not propagate to COM object.
Ok I posted this issue in WCF Forum and I’ve got a simple response but it gave me a good clue. Allen Chen (The moderator) suggested me to use self-hosting for WCF instead of IIS hosting.
Self-hosted WCF was great idea! Actually it works on self-hosted. But my WCF service should be unattended so that I created a managed service for WCF hosting. To make it work I’ve created three projects. One WCF service library which is used in managed service application. And the third one is a console application for testing. I’ve called CoInitializeSecurity on constructor of my service class as following
private ServiceHost serviceHost;
public WCFServiceHost()
{
int result = CoInitializeSecurity(IntPtr.Zero, -1,
IntPtr.Zero, IntPtr.Zero,
RpcAuthnLevel.Connect, RpcImpLevel.Impersonate,
IntPtr.Zero, Convert.ToInt32(EoAuthnCap.DynamicCloaking), IntPtr.Zero);
//EventLog.WriteEntry(result.ToString());
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(ServiceImpersonate));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
It doesn’t work with built in WCF impersonation. But I used my impersonation class inside the service class to impersonate to desired user and it works.
public string GetUserNames()
{
ImpersonateClass impersonate = new ImpersonateClass();
using (impersonate.ImpersonateUser("AnotherUser",
"Domain",
"passw0rd"))
{
return DoWork();
}
}
private string DoWork()
{
string result;
COMTESTLib.TestClass obj = new COMTESTLib.TestClass();
result = string.Format("COM:{0} .Net:{1}", obj.CurrentUserName,
System.Security.Principal.WindowsIdentity.GetCurrent().Name);
return result;
}
In the console application I simply called my service like following code:
ServiceReference.ServiceImpersonateClient client = new ServiceReference.ServiceImpersonateClient(); string str = client.GetUserNames(); Console.WriteLine(str); client.Close(); Console.ReadLine(); // Returns COM:DOMAIN\ AnotherUser .Net:DOMAIN\AnotherUser
When you host WCF in IIS the process is spawned by IIS and before your code running code managed by IIS will be run in the process, which is almost out of your control. CoInitializeSecurity thus might be called before you calling it.
Hosting WCF Service in IIS and Configuration may be needed
This article is an attempt to depict steps may needed to configure IIS for hosting WCF application. An important thing that should be considered is that all user do not face following situations. First of all I try to create a simple WCF application and then I try to publish this simple WCF simple application.
In order to create a WCF application we just need to know ABC of WCF application which are Address, Binding and Contract. (You can download code from here)
First of all I created a blank solution with Visual Studio 2008 by clicking File > New > Project and selecting Other Project Types > Visual Studio Solutions > Blank Solution
I created solution named AccountSolution. I added new project named Accounting by right clicking on AccountingSolution and selecting Add > New project menu. In the next step I added reference of System.ServiceModel to project references.
I changed name of class1.cs to IAccount.cs and I added new class named AccountService.cs. Here is code for IAccount and AccountService:
IAccount.cs
using System;
using System.Text;
using System.ServiceModel;
namespace Accounting
{
[ServiceContract]
public interface IAccount
{
[OperationContract]
int GetBalance(int accountNumber);
}
}
AccountService.cs
using System;
using System.Text;
using System.ServiceModel;
namespace Accounting
{
public class AccountService : IAccount
{
#region IAccount Members
public int GetBalance(int accountNumber)
{
Random rnd = new Random(1000000);
return Convert.ToInt32(rnd.Next());
}
#endregion
}
}
I added new web site named WCFServiceAccount and added new project reference of Accounting. Since I added project reference to Accounting project, cs under App_Data folder is no longer needed. So let delete two cs file under App_Data.

I changed Service.svc source to:
<%@ ServiceHost Language="C#" Debug="true" Service="Accounting.AccountService"%>
Setting Service and end points:
In order to setService and end points I used WCF Configuration option by right-clicking on web.config.
Tip: Sometimes "Edit WCF Configuration" does not appear in right-click menu. Once open "WCF Service Configuration" from tools menu and close it, this cause menu appear next time in right click menu.
I set first service name to Accounting.AccountService by browsing Accounting.dll in bin directory.

And I set first end point contract attribute to Accounting.IAccount and delete second end point.

And at last save the WCF configuration and build solution. Before running web site let set WCFServiceAccount as startup project and set Service.svc as start page. Our web site is ready to be executed. After successful execution let host our website to local IIS. Simply website could be hosted by publishing web site to local IIS. If IIS is installed before visual studio 2008 you may not face with any following errors and simply you can jump next step.
I tried to publish WCFServiceAccount by right clicking on Web site project and selecting "…" then Local IIS but I’ve got following errors. (My windows was Vista Ultimate)
To Access local IIS Web sites, you must install the following IIS component.
- IIS 6 Metabase and IIS 6 Configuration Compatibility
- ASP.NET
- Windows Authentication

Configuring IIS to publish a web site (Specially WCF web site):
To rectify mentioned errors I’ve found a document in Technet for installing IIS6 Metabase and IIS 6 Configuration
To install the IIS 6.0 Management Compatibility Components by using the Windows Vista Control Panel
- Click Start, click Control Panel, click Programs and Features, and then click Turn Windows features on or off.
- Open Internet Information Services.
- Open Web Management Tools.
- Open IIS 6.0 Management Compatibility.
- Select the check boxes for IIS 6 Metabase and IIS 6 configuration compatibility and IIS 6 Management Console.
- Click OK.
Pasted from <http://technet.microsoft.com/en-us/library/bb397374.aspx>
Following image shows how to install "IIS6 Metabase and IIS 6 Configuration ". Surprisingly you can set other option such as Installing ASP.NET and Windows Authentication.

Alternatively, For installing ASP.NET you can use visual studio command prompt and running aspnet_regiis with -i parameter:
aspnet_regiis -i
Publishing WCFServiceAccount to local IIS:
- Right click on WCFServiceAccount select publish from menu
- Select local IIS option
- Select create new application icon
- Type web application (e.g. WCFServiceAccount)
- Now open a browser to test your application "http://localhost/WCFServiceAccount/Service.svc"
- Then select Open button
If you get following error:
Server Error in ‘/WCFServiceAccount’ Application.Configuration ErrorDescription: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.Parser Error Message: Unrecognized configuration section system.serviceModel. Source Error:
Source File: C:\inetpub\wwwroot\WCFServiceAccount\web.config Line: 103 Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053 |
OR
|
Server Error in Application "Default Web Site/WCFServiceAccount" HTTP Error 404.3 – Not Found Description: The page you are requesting cannot be served because of the Multipurpose Internet Mail Extensions (MIME) map policy that is configured on the Web server. The page you requested has a file name extension that is not recognized, and is not allowed. Error Code: 0×80070032 Notification: ExecuteRequestHandler Module: StaticFileModule Requested URL: http://localhost:80/WCFServiceAccount/Service.svc Physical Path: E:\Projects\Learning\Blog\WCFServiceAcount\Service.svc Logon User: Anonymous Logon Method: Anonymous Handler: StaticFile Most likely causes:
What you can try:
More Information…This error occurs when the file extension of the requested URL is for a MIME type that is not configured on the server. You can add a MIME type for the file extension for files that are not dynamic scripting pages, database, or configuration files. Process those file types using a handler. You should not allows direct downloads of dynamic scripting pages, database or configuration files.
|
You should register service model according to following steps:
-
Run a Visual studio Command prompt
-
Enter "cd c:\windows\Microsoft.Net\Framework\v3.0\Windows Communication Foundation\" And press enter
- Run "servicemodelreg -i"

