Mélange
the colors of my life

Getting Access Denied Errors in your WCF service or ASP.NET application ?

Standard

We are using impersonation in our WCF Service so that credentials of the user can flow to the backend layer (where authorization is done). Strangely we were getting Access Denied errors when the client tries to connect to the service. The error message was like:

Could not load file or assembly ‘MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. Access is denied.

This was very frustrating to say the least. The first thing to do was search the internet with the error message and sure enough, several other people had faced the same issue but nobody had a good solution for the problem. The problem was that the code was running under the identity of the user (because we were using impersonation) and when the assemblies were shadow copied to the “Temporary ASP.NET Files” directory (C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files), the user did not have write permissions to that directory and hence the Access denied error.

Note: I should say that the Fusion Log Viewer was extremely helpful in identifying the problem and helping to make sure that the problem was resolved.

The obvious solution is to give users write permission to that folder. The testing team decided that this could a potential security issue (even though this was an internal application and permissions were given only to authenticated users). So we began hunting for other solutions and came up with more solutions.

  • Run aspnet_regiis –ga “authenticated users”.

This seemed to fix the problem, but it turned out that it was just a variation of granting authenticated users permission to the Temporary ASP.NET Files folder. What this command does is add the user/user-group to the IIS_USRS groups which is already set to have modify permissions on the Temporary ASP.NET Files folder. It works, but we are back to square one.

  • Disable Shadow copying of assemblies

As I mentioned earlier, the problem was occurring while shadow copying the assemblies to the temp location. The primary purpose of shadow copying is to do dynamic compilation and hot-swapping files. Dynamic compilation does not apply to WCF as much as for ASP.NET. Also we were not very concerned about the hot-swapping of files, so this was a credible option for us. But what concerned us was that we couldn’t find any info about any other side effects of disabling shadow copying. To disable shadow copy, add the following in your web.config inside the configuration section.

<system.web>
    <hostingEnvironment shadowCopyBinAssemblies="false"/>
</system.web>

The good thing about this option is that it does not require a code change and is easy to revert and also there doesn’t appear to be any security issues.

  • Move impersonation to the end of the call stack

Since the problem occurs because the assembly loading happens in the identity of the user, we could do away with declarative impersonation and do an imperative style impersonation where impersonation is done only when making calls to the backend system. To make it more clear, we were doing impersonation like:

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public Response DoSomething(Request request)
{
        return request.Execute();
}
Instead we could do impersonation only while calling the backend code:
WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
if (callerWindowsIdentity == null)
{
    throw new InvalidOperationException("The caller cannot be mapped to a WindowsIdentity");
}

using (callerWindowsIdentity.Impersonate())
{
    // Make backend calls
} 

This is definitely a good solution, but has atleast two drawbacks. The first problem (not a big one) is that it requires a code change. The second problem is a performance one and happens only if the backend calls are webservice calls. The reason for this is that the webservice calls usually require a XmlSerializers dll which is generated by Visual Studio and usually deployed along with the application. If this assembly is not present, the runtime will create one dynamically. This can cause a perf hit. Since we do impersonation before making the backend call, the XmlSerializer assembly is loaded in the identity of the user and will fail. But the CLR, failing to bind the assembly, will synthesize one for you thus causing a perf hit.

If your backend calls are not webservice calls, then this is a reasonable workaround for you.

  • Pre-load the assemblies

What we understood from the Fusion Logs was that the assembly loading was happening under the identity of the end user who does not have adequate permissions. So one thing we can do is to pre-load the assemblies when the service is running as the network service account. To do this, we created a Global.asax file and in the Application_Start event handler, we refer to types in all the assemblies of the service, thus forcing them to be loaded even before the first request is processed. The code looks something like this:

namespace MyService
{
    public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)         
        {
            //Make sure all the dlls are loaded
            Action action = new Action(null);
            EntityOperations.EntityOperationsFactory.CreateOperation();
            DataAccess.DaoFactory.CreateDao(); 
            WebServiceLibrary.WebServiceGateway.Initialize(null);
        }
     }
}

Using the Fusion Logs we were able to see that the assemblies were getting loaded under the identity of the network service account. We could also see that the XmlSerializers were also getting loaded correctly.

This solution might feel a little icky because of its unconventional nature but I think it is a brilliant solution and it seems to work correctly. We have decided to adopt this solution for our project.

  • Change the shadow copy directory to a directory inside the website directory

Frankly I never tried this one out and don’t know if it works, but it is worth some investigation if none of the solutions outlined above works for you.

I will make a follow up post or edit this one, if I find problems with the solutions mentioned here or if I find better solutions.

November 4, 2009 .NET, C#, Technical, WCF pc
6 Responses to Getting Access Denied Errors in your WCF service or ASP.NET application ?
  • .entrypoint » Blog Archive » Why we should be testing the release build and not the debug build

    [...] I mentioned in a previous post, one of solutions for the access denied issue was to pre-load the assemblies in the Global.asax [...]

    November 6, 2009 @ 1:20 pm | Permalink
  • Perry

    Came across your posting when I was just searching for a solution to the same issue. We’ve had this issue in our framework for the past 2mths+.
    Good to know that some proposals/ideas I had shared with the team are similar to what you’ve mentioned here : (1) disable shadow copy (2) imperative model impersonation (3) pre-load assemblies.
    In the end we should try out preloading assemblies from global.asax. Nice simple solution there.
    Cheers.

    December 3, 2009 @ 6:56 pm | Permalink
  • pc

    I am glad to hear that you were able to solve the problem, Perry.

    March 30, 2010 @ 12:20 pm | Permalink
  • bharat

    look into ur database connections

    June 9, 2010 @ 10:49 pm | Permalink
  • Aaron

    Great post! We were seeing the same error with our WCF application that was described in this post.
    WCF application, Impersonation, Server 2008 R2
    In our environment we were seeing this problem occurring intermittently. Sometimes the application would work properly, but other times we would receive the Access Denied error and we couldn’t figure out why.
    After reading this article and carefully considering how our application was working we identified the problem.
    Our issue was that the user that performed the installation and did the configuration was a local administrator who had Full Control on the C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files folder. When this user tested the application IIS created the shadow volume and everything worked as expected. IIS defaultly recycles application pools every 1740 minutes. After the recycle occurred users that did not have proper rights on the ASP.NET Files folder were the first users to use the application and since the shadow copy needed to occur again, it failed due to incorrect rights for the impersonated users.
    During the troubleshooting process we would restart the application pool, and then test the application and everything would work properly, but we’d get a call later that the problem had reoccurred. By taking the above articles information into consideration we were eventually able to determine that our problem was related to the recycle and our user permissions. In our instance we were able to grant the users Full Control of the ASP.NET Files folder and this resolved our issue.

    December 29, 2011 @ 7:58 am | Permalink
  • AbigailJenkinsJr

    Fixed my issue. very cool. thanks!!!

    June 14, 2012 @ 7:36 am | Permalink

Leave a Reply

* Copy This Password *

* Type Or Paste Password Here *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Font Size
Decrease Size Default Size Increase Size
Select Skin
Select Underlay Background
Select Overlay Background
Scheme Switcher Toggle