简体   繁体   中英

Encrypting XML custom configuration file

I have this method which populates an object from my XML "custom configuration" config file:

public static BindingList<StationConfiguration> GetStationsFromConfigFile()
{
    string xmlDocumentText = File.ReadAllText(GetConfigFilePath());
    var doc = new XmlDocument();
    doc.LoadXml(xmlDocumentText);

    BindingList<StationConfiguration> stations = new BindingList<StationConfiguration>();
    foreach (XmlNode node in doc.DocumentElement["StationsSection"].ChildNodes[0].ChildNodes)
    {
        stations.Add(
            new StationConfiguration(
                node.Attributes["Comment"].Value
                , node.Attributes["FtpUsername"].Value
                , node.Attributes["FtpPassword"].Value
                , node.Attributes["DestinationFolderPath"].Value
            ));
    }

    return stations;
}

As you can see, I'm using File.ReadAllText to pull the contents of the XML config file into a String.

This all works well for a non-encrypted config file. But now I need to encrypt it. The way MSDN suggests doing that begins like this:

System.Configuration.Configuration config =
    ConfigurationManager.OpenExeConfiguration(
    ConfigurationUserLevel.None);

(Incidentally, when I look at the config.FilePath property, it shows me the correct path of the XML config file, just having an extra ".config" extension for some strange reason. It ends with ".exe.config. config " for some odd reason. But I digress... )

This is my StationConfigurationSection class:

public class StationConfigurationSection : ConfigurationSection
{
    [ConfigurationProperty("Stations", IsDefaultCollection = false)]
    [ConfigurationCollection(typeof(StationCollection),
        AddItemName = "add",
        ClearItemsName = "clear",
        RemoveItemName = "remove")]
    public StationCollection Stations
    {
        get
        {
            return (StationCollection)base["Stations"];
        }
    }

    public override bool IsReadOnly()
    {
        return false;
    }
}

My complete XML config file looks like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="StationsSection" type="EcFtpClient.StationConfigurationSection, EcFtpClient" />
  </configSections>
  <StationsSection>
    <Stations>
      <add Comment="ABC" FtpUsername="eliezer" FtpPassword="secret" DestinationFolderPath="C:\Users\eliezer\Desktop\local dest" FtpTimeoutInSeconds="30" FtpHostname="ftp://192.168.1.100/" FtpFolderPath="" />
    </Stations>
  </StationsSection>
  <startup>
    <supportedRuntime version="v2.0.50727" />
  </startup>
  <appSettings>
    <add key="NameOfService" value="ECClient" />
    <add key="PollingFrequencyInSeconds" value="60" />
  </appSettings>
</configuration>

I would like to use the MSDN System.Configuration approach, since it makes en/de-cryption very easy, but how can I blend their approach with what I have to make it work?


-- UPDATE --
I've got the loading of the file but am still stuck when it comes to saving the file.

I've changed the loading method (at the very top of this question) to this:

public static BindingList<StationConfiguration> GetStationsFromConfigFile()
{
    Configuration config = ConfigurationManager.OpenExeConfiguration(GetConfigFilePath());
    StationConfigurationSection stationsConfig = (StationConfigurationSection)config.GetSection("StationsSection");
    var stationCollection = ((StationCollection)stationsConfig.Stations);

    BindingList<StationConfiguration> stationsToReturn = new BindingList<StationConfiguration>();

    for (int index = 0; index < stationCollection.Count; index++)
    {
        stationsToReturn.Add(
            new StationConfiguration(
                stationCollection[index].Comment,
                stationCollection[index].FtpUsername,
                stationCollection[index].FtpPassword,
                stationCollection[index].DestinationFolderPath)
            );

    return stationsToReturn;
}

What that gets me is the ability to load a file regardless of whether it's encrypted or not - it loads successfully. That's great.

But I'm still not sure how to get saving working. Here's my save method:

public static void SaveStationsToConfigFile(BindingList<StationConfiguration> updatedStations, bool isConfigToBeEncrypted)
{
    string configFilePath = GetConfigFilePath();

    var xDoc = XDocument.Load(configFilePath);
    var xDeclaration = xDoc.Declaration;
    var xElement = xDoc.XPathSelectElement("//StationsSection/Stations");

    // clear out existing station configurations
    xDoc.Descendants("Stations").Nodes().Remove();

    foreach (var station in updatedStations)
    {
        xElement.Add(new XElement("add",
                new XAttribute("Comment", station.Station),
                new XAttribute("FtpUsername", station.Username),
                new XAttribute("FtpPassword", station.Password),
                new XAttribute("DestinationFolderPath", station.FolderName),
                new XAttribute("FtpTimeoutInSeconds", 30),
                new XAttribute("FtpHostname", GetEnvironmentAppropriateFtpHostName()),
                new XAttribute("FtpFolderPath", GetEnvironmentAppropriateFtpFolderPath())
        ));
    }

    xDoc.Declaration = xDeclaration;
    xDoc.Save(configFilePath);
}

And in order to save it with the protection/encrpytion, I need to do something like this - in other words, using the System.Configuration.Configuration objects:

stationsConfig.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
stationsConfig.SectionInformation.ForceSave = true;
objConfig.Save(ConfigurationSaveMode.Modified);

But I'm currently still doing the save with XDocument.Save ...

Is there a way to convert my XDocument into a System.Configuration.Configuration compatible object?
The hack that comes to mind is after the call to XDocument.Save - to load it and save it again using the System.Configuration.Configuration stuff. But that's a hack...

I believe you have to play along with the configuration settings framework . Rather than trying to open the xml file yourself, you need to create a descendant of ConfigurationSection .

That way it will read and write from the encrypted configuration for you.

It looks like you already started that route ( EcFtpClient.StationConfigurationSection ), but you didn't include any of that code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM