Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access denied exception with RazorEngine 3.5 #217

Closed
Krashlog opened this issue Jan 22, 2015 · 7 comments
Closed

Access denied exception with RazorEngine 3.5 #217

Krashlog opened this issue Jan 22, 2015 · 7 comments

Comments

@Krashlog
Copy link

Hi,

We're using RazorEngine to generate emails in an ASP.Net Web Application. Since updating our code to version 3.5, the template compiling fails with the following stack trace:

Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

The easiest way to test this is simply to create a blank website in Visual Studio, add the RazorEngine package, and plug the basic "Hello World" sample template. With 3.4.x, the code will run just fine. I've tracked the error to the CompileType method, when the process tries to load the generated assembly in the Windows Temp folder.

C:\Windows\Temp\RazorEngine_grceyklj.1f1\CompiledRazorTemplates.Dynamic.RazorEngine_6aa243ea4a104b1f8d7036145a4c87a0.dll
Event Class: File System
Result: ACCESS DENIED
Impersonating: DMZ\iusr_web

Note that our websites are using ASP.NET Impersonation, and the impersonated user is "iuser_web" ,from our DMZ domain. Giving this user read access to the C:\Windows\Temp\ folder on the local machines fix the problem, and the templates are generated correctly. However, I'm not sure if this is the right course of action, since this used to work perfectly in 3.4.x.

Is this a new requirement for 3.5 ?

Thanks,
Shaun

@matthid
Copy link
Collaborator

matthid commented Jan 22, 2015

First of all thanks for this detailed error report!

Yes, there were changes in that part of RazorEngine:
Instead of relying on the build in temporary compilation we now specify the path manually.

  • Helps with debugging templates (and to provide nice stack traces).
  • The default loading mechanism of CodeDom (Load(byte[])) defeats the sandbox.
  • Allows custom caching provider to pick up the assembly and cache it in the filesystem.
    Unfortunately it seems to fail in your scenario, but I'm not sure why that is the case. Especially I cannot see why you can write in that directory but not read?

The first things that come into my mind:

  • Can you try GACing the RazorEngine assembly? (If you do not to run templates with full trust use the isolation API)
  • Would it help you if there was an API to specify the path manually?

The reason specifying the path manually is problematic: If you do not use the Isolation API you cannot clean up that path! There is no way to unload the Assembly and therefore to release the file lock.

I also decided agains a single "RazorEngine" directory in Temp as that would potentially lead to permission problems when used in different user accounts. That's why RazorEngine creates the folders starting with "RazorEngine_". It would be enough to allow RazorEngine to read those. In fact it should be enough if RazorEngine could read the folders it created itself... Any idea why that is not the case?

@Krashlog
Copy link
Author

Thanks for the reply.

Unfortunately it seems to fail in your scenario, but I'm not sure why that is the case. Especially I cannot see why you can write in that directory but not read?

I dug a little deeper and found something interesting : the call to CompileAssemblyFromSource doesn't carry forward the impersonated user, CSC.exe is thus executed under the AppPool identity. The DLL is written using that identity, but the impersonated user doesn't have read access to the resulting DLL.

I have tried running the website with Full trust, and also tried adding RazorEngine to the GAC. The results are the same, the impersonated user gets ignored when CompileAssemblyFromSource is called. I'm not sure about the impact of using the Isolation API, do you think this could possibly fix my problem?

I understand the design decision behind these changes, and in the meantime I'm running tests with read rights explicitly given to the Temp folder. Let me know how I can be of further help.

@matthid
Copy link
Collaborator

matthid commented Jan 22, 2015

Can you try with the https://github.com/Antaris/RazorEngine/tree/feature/workaround_impersonation branch?

git clone -b feature/workaround_impersonation git@github.com:Antaris/RazorEngine.git
cd RazorEngine
build.cmd

Should build you the assembly in the build\net45 folder.

@Krashlog
Copy link
Author

The branch fixed the issue!

The impersonated user is no longer being used, and the templates are compiled correctly.

Thanks a lot.

@matthid matthid removed the need-info label Jan 22, 2015
@matthid
Copy link
Collaborator

matthid commented Jan 22, 2015

Good, thanks for testing this. I will make a 3.5.1 release when I have fixed the mono build.

Until then, if you want to use the official version you can work around the bug yourself:

(new PermissionSet(PermissionState.Unrestricted)).Assert();

WindowsImpersonationContext wic = WindowsIdentity.Impersonate(IntPtr.Zero);
try
{
    // Failing razorengine code.
}
finally
{
    wic.Undo();
}

Sadly I found no way to unit test this to prevent future regressions :(. Do you have an idea?

matthid added a commit that referenced this issue Jan 23, 2015
@Krashlog
Copy link
Author

For my use case, we'd need to properly mock IIS behavior when using ASP.Net Impersonation. Unit testing and mocking HttpContext over Impersonation can be a total PITA. All my suggestions would amount to integrated testing, sorry.

@matthid
Copy link
Collaborator

matthid commented Jan 23, 2015

I think its "ok" without unit test as there is a workaround, so even if we introduce this again in the future: one can use the code from above to work around this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants