SharePoint Web Part Embedded Resource Permissions

It is a normal expectation for companies to embed resources like javascript, CSS and other resources in an assembly.  Web Parts are no exceptions.  For those of you that deploy everything to the GAC, you can disregard the remainder of this post.  The rest of you, bear with me.  If we are not deploying to the GAC we are typically deploying to the bin.  The bin directory in SharePoint has the following permissions by default; full control for SYSTEM, Administrators and WSS_ADMIN_WPG groups, and read-only access for WSS_WPG group.  This is not sufficient for embedded resources to be loaded by accounts that don't exists in one of these groups.  If you run an assembly with embedded resources with anything other than an account that is in one of these groups you will get the following error:

 Exception raised when trying to access embedded resources:
System.UnauthorizedAccessException: Access to the path 'C:\inetpub\wwwroot\wss\VirtualDirectories\80\bin\SampleWP.DLL' is denied. 
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
at System.IO.File.GetLastWriteTimeUtc(String path) at System.IO.File.GetLastWriteTime(String path) 
at System.Web.Handlers.AssemblyResourceLoader.GetAssemblyInfoWithAssertInternal(Assembly assembly) 
at System.Web.Handlers.AssemblyResourceLoader.GetAssemblyInfo(Assembly assembly) 
at System.Web.Handlers.AssemblyResourceLoader.GetWebResourceUrlInternal(Assembly assembly, String resourceName, Boolean htmlEncoded) 
at System.Web.Handlers.AssemblyResourceLoader.GetWebResourceUrl(Type type, String resourceName, Boolean htmlEncoded) 
at System.Web.UI.ClientScriptManager.GetWebResourceUrl(Page owner, Type type, String resourceName, Boolean htmlEncoded) 
at System.Web.UI.ClientScriptManager.RegisterClientScriptResource(Type type, String resourceName) 
at TestWebPart.ResourcePermissionTest.OnPreRender(EventArgs e)

The assembly doesn't have permission to access the bin directory.  If you don't get this error do an IIS reset and then access the web part as a user that isn't in one of these groups.  The difficult part of figuring this out was that if a user with permissions to write to the directory first accesses the web part it will render properly, not only for that user, but any user thereafter.  This will happen until the cache is exhausted.  So even during the debugging process I was wondering what the heck I just saw a couple of times.

On the surface the easy solution is to change the permissions and set 'everyone' to have read / write access and move on.  What you will notice is that SharePoint will reset these permissions back to the standard after certain events.  One of those events is deploying a solution.  If you watch the directory you will notice that the bin permissions are recreated when this happens.  The bin directory is actually deleted and recreated.  So while the 'everyone' account will work temporarily, it isn't a long term solution.

What about CAS?  Doesn't work.  Contrary to some of the other posts out there about this this isn't a CAS issue.  Granting the assembly 'Full' trust doesn't change the fact that an account that doesn't have access to the directory needs to write to it.  While you can set the web.config and disable impersonation or create a CAS policy that doesn't impersonate, this isn't the best solution in cases where you need to impersonate the user.  Windows Auth. comes to mind.  It would allow you to take the non-impersonated account and add them to one of the built-in groups so the web part would function properly.  This probably isn't an acceptable solution if you are an ISV or third party looking to distribute your web part to other parties.  They may not be open to adding least privilege accounts to groups on their servers

One solution that does work is creating a folder in the web application directory and changing the web.config to add a probingPath in order to help the .NET runtime locate your assembly.  By creating your own directory you control the permissions and they aren't reset by SharePoint.  Your installation and setup are a little more trouble, but you have a solution that should work long term without sacrifices to the functionality of SharePoint or, most importantly, your web part.