dotnet security:
Hi I have developed a web application (ASP.NET 2.0 - C#) which uses a COM dll (Delphi 7) to carry out some server side operations. The COM dll internally creates some threads to connect to some asynchronous APIs which are proprietary APIs of our organization. The COM dll has following two methods of handling various calls coming from the web app. 1. Synchronous: For some operations, the COM dll does all the processing on the web application thread. 2. Asynchronous: For some operations, the COM dll does the processing in one of its internal threads. The COM dll makes the web application thread wait until it completes the anychronous processing. The web thread is then released. The web application functionality includes a facility to start/stop some windows services. For some technical and business domain reasons, this facility is sometimes invoked using the synchronous method and sometimes invoked using the asynchronous method (i.e. form inside an internal thread of the COM dll). During development I found that it is not possible to start/stop a service from an ASP.NET application because it runs in the context of the ASPNET user account. ASPNET account does not have enough permissions/privileges to allow it to start/stop a service. Therefore I was getting an 'Access is denied' error (GetLastError = 5). To overcome this issue I now use the impersonation in my web application by setting the '<identity impersonate="true" />' setting in the 'web.config' file. I also set IIS directory security settings to allow all requests coming to my web app to be authenticated using a local admin account. As a result, the web application now runs in the context of a local admin account. This solution works perfectly for the synchronous method mentioned above. However, when I try to start/stop a windows service from one of the internal threads of the COM dll, I still get an Access is denied error (GetLastError = 5). I have done some investigation into this. I believe that the threads created by the Delphi COM dll are still created with the security context of the primary user account, i.e. ASPNET account, instead of the security context of the imperosnated user account, i.e. a local admin account. Any calls served synchronously succeed as .NET generated threads carrying the web request have the security context of the impersonated user account. But any calls served asynchronously do not succeed as the COM dll generated threads serving the request have the security context of the primary user account, i.e. ASPNET. I need to know whether it would be possible to create the COM dll internal threads using the security context of the impersonated user. In particular I need some guidance on how to determine the identity of the impersonated user using Windows API functions (I am developing on Windows 2000 Server, Service Pack 4) and how to create the thread using the security context of the impersonated user. I can easily access any Windows API function from Delphi so any references to Windows API functions would be more than welcome. Kind regards
Adding to my post: Another possible solution in my mind is to somehow set my web application so that it uses a local admin account as the primary user, not as an impersonated user. I believe that the COM dll internal threads will then be created with the security context of the local admin account instead of the ASPNET account. I would prefer if I don't have to set anything for that in 'Machine.config'. According to my knowledge, settings in 'Machine.config' apply to all ASP.NET applications running on that machine. I would like to have a solution which only applies to my ASP.NET web application so that any other ASP.NET web application on the same machine is not effected. However, if nothing else is possible, I can consider a 'Machine.config' based solution as well. If I can get some pointers in that direction, that would also be a good solution I guess. Thanks
Hi Well, I guess I have found a solution myself. Just posting it here for benefit of anyone interested. Would also appreciate if any flaws in this solution are pointed out by anyone. I have added an event to my COM dll (lets call it 'DoImpersonate' event) which is handled by a class in my ASP.NET web application code (lets call this class as 'Impersonator'). As the first step of this solution, in the 'Session_Start' event handler of the 'Global.asax' file, I save a reference to the current WindowsIdentity object (System.Security.Principal.WindowsIdentity.GetCurrent) by assigning it to a member variable of the 'Impersonator' class. The WindowsIdentity object obtained in the 'Session_Start' is the windows identity of the impersonated user account. As I mentioned in my original post, I use '<identity impersonate="true" />' in my web.config file to force impersonation of the IIS authenticated user account. Following code snippet describes this step. void Session_Start(object sender, EventArgs e) { // 'Impersonator' is the class which handles the 'DoImpersonate' event. // It has a class member variable called 'Identity' which is an object of type // WindowsIdentity. I am assigning the current WidnowsIdentity to this variable // for later use. Impersonator.Identity = System.Security.Principal.WindowsIdentity.GetCurrent(); } The second step of this solution is to make the COM dll internal threads impersonate the identity of the WindowsIdentity object saved above. Whenever I create a thread inside my COM dll, the very first thing that I do in the thread start procedure is to raise the 'DoImpersonate' event. The event handler in 'Impersonator' class then calls the 'Impersonate' method of the WindowsIdentity object which I saved in the 'Session_Start' event handler. As the 'Impersonator' event handler is running inside the COM dll thread, this calls makes the COM dll thread impersonate the identity of the saved WindowsIdentity object. The COM dll thread is then able to do anything which the impersonated user account security context allows, such as starting/stopping the windows services. Following code snippet describes this step. class Impersonator { public WindowsIdentity Identity = null; void DoImpersonate_EventHandler() { WindowsIdentity checkIdentity = null; // At this point the thread is running in the security context of the primary // user account, i.e. ASPNET or any other account you have configured in // 'Machine.config'. checkIdentity = System.Security.Principal.WindowsIdentity.GetCurrent(); try { if (Identity != null) { // Try to impersonate the saved WindowsIdentity Identity.Impersonate(); } } catch(Exception ex) { // Handle any exceptions } // If the above 'Impersonate' call succeeds without any problem, the thread // is now running in the security context of the saved WindowsIdentity object // having the required permissions/privileges. checkIdentity = System.Security.Principal.WindowsIdentity.GetCurrent(); } } It is important to call the 'Impersonate' method of the WindowsIdentity object which represents the impersonated user account. If you call 'System.Security.Principal.WindowsIdentity.GetCurrent' inside the 'DoImpersonate' event handler before calling 'Impersonate', you will discover that the windows identiy object obtained at that point is the identity object for the local ASPNET user account (or any other user account which you have manually configured in your 'Machine.config' file). The COM dll thread is created in the security context of the ASPNET account and therefore has limited permissions/privileges. By calling the 'Impersonate' method on the saved WindowsIdentity object we make the thread impersonate the user account which is impersonated by the ASP.NET web application, thus granting the COM dll thread same permissions/privileges which are available to the impersonated user account. I have yet to test this solution thoruoghly, therefore I welcome any comments/suggestions on that. Regards
Don't see what you're looking for? Try a search.
|