Search code examples
c#asp.netpdfadminoffice-interop

Converting Word to PDF using Interop requires admin rights


First off, I know that this falls into the category of "not recommended practice", but I have a requirement to convert Word documents to PDF, via an ASP.Net site, and I have been using the Word Interop as it is free, simple to implement and Word is already installed on the server.

When I have been testing, it is working for me but after publishing users are reporting "Unauthorised access" errors. I have admin rights to the server and I found that adding the users as admin on the server works but I do not want to grant admin rights to every user.

So one of a number of things needs to happen, is there an alternative, free, library for converting a Word document to PDF that I could be using? Is there an easy way to get my users access to the Interop library without giving admin rights? Is there a way to impersonate an admin user for this part of the web application, seeing as the application requires Windows Authentication?

Is there anything else I have not thought of that could benefit me?


Solution

  • You can use impersonation to run code as a different user. There is a good impersonation class available on CodeProject here, http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User.

    Just create a new admin account on the machine with access to do what you want, store the credentials in the web.config in app settings, (encrypt them if you want to with rijandael and decrypt them with code, etc.

    But long store short, you use it like this,

    using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
    {
        //This code is running elevated as the specified user
    }
    //This code is reverted back to the previous user.
    

    I actually wrote my own web.config ConfigurationElement for storing credentials. It looks like this,

    public class CredentialConfigurationElement : ConfigurationElement
    {
        #region Properties
        [ConfigurationProperty("userName", DefaultValue="", IsRequired=true)]
        public string UserName
        {
            get { return (string)this["userName"];}
            set { this["userName"] = value; }
        }
    
        [ConfigurationProperty("password", DefaultValue = "", IsRequired = true)]
        public string Password
        {
            get { return (string)this["password"]; }
            set { this["password"] = value; }
        }
        #endregion
    
        #region Explicit Operators
        public static implicit operator NetworkCredential(CredentialConfigurationElement value)
        {
            return new NetworkCredential(value.UserName, value.Password);
        }
        public static implicit operator CredentialConfigurationElement(NetworkCredential value)
        {
            return new CredentialConfigurationElement() { UserName = value.UserName, Password = value.Password };
        }
        #endregion
    }
    

    However, to use it, you need to make a Custom ConfigurationSection, a class that inherits from ConfigurationSection and exposes the CredentialConfigurationElement as a property.

    E.g. you could make a new section called CodeImpersonatorSection : ConfigurationSection

    And in there expose the CredentialConfigurationElement as a property called ImpersonationCredentials.

    Then use (CodeImpersonatorSection)WebConfigurationManager.GetSection("/yoursectionnamehere"); to get an instance to the configuration.

    Optionally modify the Impersonator class to do that automatically, and change it to have a static method like

    Impersonator.RunUnderImpersonation(p => {
      //This code is impersonating the configured user.
    });