Access a file with a different user identity with Enterprise Services

A customer asked how they could access a file share using a different user identity. 

Imagine the scenario:  you have a web site that needs to access a UNC share, and the ASPNET process account does not have access to the UNC share.  Granting this account access to the UNC share is not an option, impersonating the logged in user is not an option because the site is running as anonymous with users of various untrusted domains accessing the site. 

I posted to an internal DL, and was offered the solution of using the LogonUser API to obtain a security token to be used for the operation.  That works, but has a significant drawback in that you as the developer needs to figure out where to store the username, domain, and password securely and how to manage access to that resource in the future... blech.  Gaylon Blank replied to my question with a different suggestion: use Enterprise Services.  Cool idea!  So, I went a-coding to figure out an example. 

 using System;
using System.EnterpriseServices;
using System.IO;

[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationName("My Enterprise Service Demo")]
[assembly: ApplicationAccessControl(false)]
[assembly: CLSCompliantAttribute(true)]

namespace Msdn.Samples.EnterpriseServices
{      

    [ComVisible(true)]    
    public class Customer : ServicedComponent
    {        
        public void DemoMethod()
        {
            StreamWriter writer = File.CreateText(@"c:\demo\test.txt");
            writer.WriteLine(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
            writer.WriteLine(System.DateTime.Now.ToLongTimeString());
            writer.Flush();
            writer.Close();
            writer.Dispose();
        }
                
    }
}

Easy enough, simple demo.  Just to make it simple on myself, I added a pre-build step:

 "C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -u "$(TargetFileName)"
"C:\Program Files\Microsoft SDKs\Windows\v1.0\Bin\regsvcs.exe" -u "$(TargetPath)"

And a post-build step:

 "C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -i "$(TargetPath)"
"C:\Program Files\Microsoft SDKs\Windows\v1.0\Bin\regsvcs.exe" "$(TargetPath)"

I went to the file directory and declined write access for myself and all other accounts, and allowed write access for a testing account (I used "demouser").  The next step was to run the COM+ server application as the user who has write access to the directory:

Set the application to run under a specified account with privileges to the directory

The final trick is to specify the impersonation level to Delegate for the COM+ server application.

Set Impersonation Level to Delegate

Bingo!  The website can then call this component, which should be a very limited account with only permissions to perform the single authenticated action.  For this example, our account only has permission to write to the UNC share. 

After a quick test, I confirmed that the file that is written contains the expected user name ("kirke1\demouser"), runs under an identity other than my own or the ASPNET worker process identity, and the application has access to a restricted resource via this component. 

The best part is that now I don't have to manage credentials anywhere.