views:

1359

answers:

3

I have found an example for encrypting a web.config during installation here, but my app is a windows service. The aspnetreg_iis method works only for web.config files.

I know how to programatically encrypt the config file, but I don't think I can do that using WiX. Am I wrong? Any ideas?

+2  A: 

You should be able to do it within a custom action. The catch that I've found is that loading an assembly for an ExeConfigurationFileMap will throw an exception, but you can handle that by adding an AssemblyResolve handler to the AppDomain. This is kind of a hack-up from a rich-client app I wrote to encrypt/decrypt protected configuration sections using a machine encryption key. It's probably not the prettiest code, but I'm hoping you can get the picture from it. This code assumes that you have the ProtectionProvider you want to use defined in the config file.

//class global
static System.Reflection.Assembly DefiningAssembly;

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);

static System.Reflection.Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
     return DefiningAssembly;
}

Then, you can load your configuration like this:

DefiningAssembly = System.Reflection.Assembly.LoadFrom("path to defining assembly for config");

//Set the Configuration using an ExeConfigurationFileMap - This works for any .config file.
ExeConfigurationFileMap CfgMap = new ExeConfigurationFileMap();
CfgMap.ExeConfigFilename = "path to config file";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(CfgMap, ConfigurationUserLevel.None);

List<string> DefiningAssemblyTypes = new List<string>();
foreach (System.Type type in DefiningAssembly.GetExportedTypes())
{
     DefiningAssemblyTypes.Add(type.Name);
}

foreach (ConfigurationSection tempSection in config.Sections)
{
     if (DefiningAssemblyTypes.Contains(tempSection.ElementInformation.Type.Name))
     {
          section = tempSection;
          break;
     }
}
ProtectionProviderName = section.SectionInformation.ProtectionProvider.Name;
section.SectionInformation.ProtectSection(ProtectionProviderName);
config.Save(ConfigurationSaveMode.Minimal, true);

I hope this helps you, best of luck.

AJ
+1  A: 

Here is what I ended up with...

I used WiX and DTF to created a managed code Custom Action to encrypt a given section of a config file:

    public static void EncryptConfig(Session session)
    {

        var configPath = session["APPCONFIGPATH"];
        var sectionToEncrypt = session["SECTIONTOENCRYPT"];

        var fileMap = new ExeConfigurationFileMap();
        fileMap.ExeConfigFilename = configPath;
        var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
        ConfigurationSection section = configuration.GetSection(sectionToEncrypt);

        if (!section.SectionInformation.IsProtected)
        {
            section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
            section.SectionInformation.ForceSave = true;
            configuration.Save(ConfigurationSaveMode.Modified);

        }
    }

Part of my lack of understanding that prompted this question was not knowing that you can safely create custom actions in managed code using DTF. Documentation is sparse on DTF, but once you get it working, it is great.

I found that this only worked if I scheduled the custom action after InstallFinalize.

Here is the WiX config to make it happen:

<InstallExecuteSequence>
  <Custom Action="EncryptConfigurationFiles" After="InstallFinalize" />
</InstallExecuteSequence>

<Fragment>
    <Binary Id="YourProject.CustomActions.dll" SourceFile="$(var.YourProject.CustomActions.TargetDir)$(var.YourProject.CustomActions.TargetName).CA.dll" />
    <CustomAction Id="EncryptConfigurationFiles" BinaryKey="YourProject.CustomActions.dll" DllEntry="EncryptConfig" Return="check" />
</Fragment>

These blogs/sites helped me get there and much of the code from above was derived from them:

http://geekswithblogs.net/afeng/Default.aspx http://blog.torresdal.net/2008/10/24/WiXAndDTFUsingACustomActionToListAvailableWebSitesOnIIS.aspx http://blogs.msdn.com/jasongin/archive/2008/07/09/votive-project-platform-configurations.aspx

@PITADeveloper... Thanks for the response. I found that I did not need to load the assembly to encrypt the config file.

If you use this, you should use a try catch and return an ActionResult... The above is pseudo-code.

Finally, I'm using the DataProtectionConfigurationProvider. For the RSA Provider, I think there are a couple more hoops to jump through.

I hope this helps someone!

JasonS
Nice! This will certainly help me in the future.
AJ
A: 

I am trying to implement this exact same behavior using WIX and custom actions. For some reason, section.SectionInformation.IsProtected() always returns true for me in the custom action DLL, even though the section is not yet encrypted. Has anyone encountered this? Even if I bypass this check and I tell it to encrypt my section, the config file's section contents are not encrypted once the installer finishes.

RaduN