Ahmadreza's Notes

On Software Development

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.

Advertisements

Written by Ahmadreza Atighechi

September 16, 2010 at 5:19 pm

Posted in Blog

Tagged with , ,

16 Responses

Subscribe to comments with RSS.

  1. Such a great article giving some great information genuinely explaining some of the key things which you need to be aware of in particular about the part relating to getting some couseling prior to getting life insurance, so many people don’t even consider it.

    lifeinsurance

    December 14, 2010 at 3:11 am

  2. Such a great article giving some great information genuinely explaining some of the key things which you need to be aware of in particular about the part relating to getting some couseling prior to getting a loan consolidation, so many people don’t even consider it.

    studentloanconsolidation

    December 15, 2010 at 4:16 am

  3. This is very common in all parts of the world is not enough what we do

    Recambios benelli

    December 30, 2010 at 7:40 pm

  4. Your blog is really excellent. It would be great if you can provide more details about it.

    send flowers to brazil

    January 3, 2011 at 9:37 pm

  5. Outstandingly enlightening many thanks, I do believe your trusty visitors might possibly want considerably more posts like that keep up the good hard work.

    best printers

    January 11, 2011 at 5:12 pm

  6. Felicitaciones siguán publicando

    TARJETAS DE VISITA

    January 19, 2011 at 12:10 pm

  7. I like the code that you have shared. I was looking for this specific information. Thanks for sharing and keep up the good work.

    car reviews

    January 20, 2011 at 5:57 am

  8. Thanks for your post, but my script doesn’t work still (I use only some hints from your post).

    Viagra kaufen

    February 1, 2011 at 5:29 am

  9. 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

    directory

    February 4, 2011 at 10:27 am

  10. good ihave learn more thanks

    laser engraving machine

    February 10, 2011 at 12:25 am

  11. Thanks, you detailed guide solved a big problem for me. I like how you explain things.

    iPhone app development

    February 25, 2011 at 6:18 am

  12. Hello there I reach your site by mistake when i was browsing Google for this wii concern, I have to say your internet site is really helpful I also love the design, its amazing!. I dont have that much time to go through all your post at the moment but I’ve bookmarked your site and also add your RSS feeds. I will likely be back in a day or two. thanks for a awesome web page.

    germanium suppliers

    February 28, 2011 at 11:29 pm

  13. bon courage

    failles de sécurité

    March 1, 2011 at 4:24 pm

  14. Nice post mate

    SJR Builders

    March 11, 2011 at 8:22 pm

  15. I have flair in writing and wish to grow ahead in the same field. Can you help me out in knowing how do you manage to be so good and perfect in your writing? I want to know if there is any coaching class or exams that I may have to join to polish my English language.

    Generic Viagra

    March 15, 2011 at 10:07 pm


Comments are closed.

%d bloggers like this: