ConfigurationErrorException when reading protected config section

G

Guest

I've created a custom configuration section that inherits (naturally) from
System.Configuration.ConfigurationSection. The configuration section is
working 99% fine, however I keep coming across a ConfigurationErrorException
whenever I do the following:

1. Modify and save the section in code using the
System.Configuration.Configuration.Save().
2. Refresh teh section using ConfigurationManager.RefreshSection
3. Encrypt the section, force save and save. Refresh the section using
ConfigurationManager.RefreshSection
4. Attempt to load the section from the configuration file via
ConfigurationManager.GetSection - throws exception due to the
configProtectionProvider attribute being present.

If I save the section and then restart my application, everything works
hunky dory... if I don't restart the app after encrypting/decrypting,
however, all heck breaks loose next time I try and read the section.

What's wrong? I thought calling ConfiguratoinManager.RefreshSection would
do the trick (it does the trick after I encrypt/decrypt the connectionStrings
section).

Thanks in advance.

- ryan.
 
G

Guest

Sorry - RefreshSection is *not* working for my connection strings. So I'm
encrypting sections, refreshing them, but then cannot read from them.
 
S

Steven Cheng[MSFT]

Hello Ryan,

As for the .net 2.0 configuration encryption and section refresh problem
you mentioned, I've just performed some tests according to your description
in my local environment. Here is my test results and some suggestion on
this:

1. When perform the configuration section protection, we can choose which
provider to use, there're two built-in providers(DPAPI provider and RSA
provider). Based on my test, the problem (ConfigurationErrorException will
occur when we use DPAPI provider , but not when using RSA provider).

2. After we have modified the configuration(any sections in it) and save it
to file and refresh the certain sections, we can use the original
configuration object to query the section data again or construcut a new
configuration object(through ConfigurationManager.OpenExeConfiguration ).
And I found that the exception will occur when we use the original
configuration object , but not occur if we reconstruct/reload a new
configuration object(from exe config file).

Therefore, I think the cause of the problem is that when using DPAPI
provider, after refresh the certain Section, the old configuration object
lose the related encryption information(since the informations first
constructed after we protect that section) and result the sequential
loading from the file failes....(it dosn't know that the section is
protected...).

If you're using the DPAPI provider("DataProtectionConfigurationProvider"),
you can consider reload a new configuration object instead of using the
original one. Here is a workable sample console application(not sure
whether you prefer VB.NET or C#, please let me know if you prefer VBNET
one):

=======================================
namespace EncryptSectionConsole
{
class Program
{
static void Main(string[] args)
{
Run();
}


static void Run()
{

Console.WriteLine("press any key to dump the
connectionstrings...");
Console.ReadLine();

DumpConnectionStrings();

Console.WriteLine("press any key to encrypt the
connectionstrings...");
Console.ReadLine();

EncryptConnectionStrings();

Console.WriteLine("press any key to dump the
connectionstrings...");
Console.ReadLine();



NewDumpConnectionStrings();

//will result exception
//DumpConnectionStrings();


}

static void DumpConnectionStrings()
{
foreach(ConnectionStringSettings connstr in
ConfigurationManager.ConnectionStrings)
{
Console.WriteLine("name: {0}, connstring: {1}",
connstr.Name, connstr.ConnectionString);
}
}

static void NewDumpConnectionStrings()
{
Configuration config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

foreach (ConnectionStringSettings connstr in
config.ConnectionStrings.ConnectionStrings)
{
Console.WriteLine("name: {0}, connstring: {1}",
connstr.Name, connstr.ConnectionString);
}
}

static void EncryptConnectionStrings()
{
Configuration config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

config.ConnectionStrings.SectionInformation.ForceSave= true;

config.ConnectionStrings.SectionInformation.ProtectSection("DataProtectionCo
nfigurationProvider");

config.Save(ConfigurationSaveMode.Modified);


Console.WriteLine("press any key to refresh the section....");
Console.ReadLine();

config.ConnectionStrings.SectionInformation.ForceSave = true;
config.ConnectionStrings.ConnectionStrings.Add(new
ConnectionStringSettings("new connstr", "new value"));


config.Save(ConfigurationSaveMode.Modified);




ConfigurationManager.RefreshSection("connectionStrings");


}


}
}
================================

Hope this helps.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



==================================================

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.



Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.

==================================================



This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Steven,

Thanks for the reply. I'm finding this is occuring regardless of which
encryption method I chose (dpapi or rsa). It's really too bad that I have to
load in a new config. To me that seems like a workaround. The
ConfigurationManager should know what to do after I call RefreshSection, and
I shouldn't have to explicitly read from the disk. This becomes even more
important when we start thinking of caching.

For example - in our situation, I have a low-level library that access
connection string information using ConfigurationManager.GetSection. My
application that utilizes the low-level library, however, encrypts the
connection strings section at runtime. This means that, in order for the low
level library to always function correctly, it must always read from disk
rather than the once-only cached version returned by
ConfigurationManager.GetSection - regardless if the section was refreshed.

Is this not a bug in ConfigurationManager?

Steven Cheng said:
Hello Ryan,

As for the .net 2.0 configuration encryption and section refresh problem
you mentioned, I've just performed some tests according to your description
in my local environment. Here is my test results and some suggestion on
this:

1. When perform the configuration section protection, we can choose which
provider to use, there're two built-in providers(DPAPI provider and RSA
provider). Based on my test, the problem (ConfigurationErrorException will
occur when we use DPAPI provider , but not when using RSA provider).

2. After we have modified the configuration(any sections in it) and save it
to file and refresh the certain sections, we can use the original
configuration object to query the section data again or construcut a new
configuration object(through ConfigurationManager.OpenExeConfiguration ).
And I found that the exception will occur when we use the original
configuration object , but not occur if we reconstruct/reload a new
configuration object(from exe config file).

Therefore, I think the cause of the problem is that when using DPAPI
provider, after refresh the certain Section, the old configuration object
lose the related encryption information(since the informations first
constructed after we protect that section) and result the sequential
loading from the file failes....(it dosn't know that the section is
protected...).

If you're using the DPAPI provider("DataProtectionConfigurationProvider"),
you can consider reload a new configuration object instead of using the
original one. Here is a workable sample console application(not sure
whether you prefer VB.NET or C#, please let me know if you prefer VBNET
one):

=======================================
namespace EncryptSectionConsole
{
class Program
{
static void Main(string[] args)
{
Run();
}


static void Run()
{

Console.WriteLine("press any key to dump the
connectionstrings...");
Console.ReadLine();

DumpConnectionStrings();

Console.WriteLine("press any key to encrypt the
connectionstrings...");
Console.ReadLine();

EncryptConnectionStrings();

Console.WriteLine("press any key to dump the
connectionstrings...");
Console.ReadLine();



NewDumpConnectionStrings();

//will result exception
//DumpConnectionStrings();


}

static void DumpConnectionStrings()
{
foreach(ConnectionStringSettings connstr in
ConfigurationManager.ConnectionStrings)
{
Console.WriteLine("name: {0}, connstring: {1}",
connstr.Name, connstr.ConnectionString);
}
}

static void NewDumpConnectionStrings()
{
Configuration config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

foreach (ConnectionStringSettings connstr in
config.ConnectionStrings.ConnectionStrings)
{
Console.WriteLine("name: {0}, connstring: {1}",
connstr.Name, connstr.ConnectionString);
}
}

static void EncryptConnectionStrings()
{
Configuration config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

config.ConnectionStrings.SectionInformation.ForceSave= true;

config.ConnectionStrings.SectionInformation.ProtectSection("DataProtectionCo
nfigurationProvider");

config.Save(ConfigurationSaveMode.Modified);


Console.WriteLine("press any key to refresh the section....");
Console.ReadLine();

config.ConnectionStrings.SectionInformation.ForceSave = true;
config.ConnectionStrings.ConnectionStrings.Add(new
ConnectionStringSettings("new connstr", "new value"));


config.Save(ConfigurationSaveMode.Modified);




ConfigurationManager.RefreshSection("connectionStrings");


}


}
}
================================

Hope this helps.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



==================================================

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.



Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.

==================================================



This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

Steven Cheng[MSFT]

Thanks for your reply Ryan,

I've retested the program, yes, you're right, the problems occurs for both
RSA or DPAPI provider. I agree that this should be an serious problem with
the configurationManager. Currently I'll consult some other engineers on
this and check whether this is an existing issue that is recorded, I'll
update you as soon as I get any udpate.

Thanks for your patience.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

Steven Cheng[MSFT]

Hello Rayn,

I've performed some further test and research on the problem behavior and
found the following difference when accessing the configuration Section
through different means. The "ConfigurationErrorException" only occurs
when I run the "ErrorTest1()" below first time, but does not occur when run
the "ErrorTest2()" below. It seems the problem is specific to the
ConfigurationManager.ConnectionStrings static property.

I'd like to confirm whether you're getting the same behavior as my local
test? If so, I would forward this to some other product engineers for
further investigation:


==========test code 1===========
static void ErrorTest1()
{

foreach (ConnectionStringSettings connstr in
ConfigurationManager.ConnectionStrings)
{
Console.WriteLine("name: {0}, connstring: {1}",
connstr.Name, connstr.ConnectionString);
}


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



config.ConnectionStrings.SectionInformation.ForceSave = true;

config.ConnectionStrings.SectionInformation.ProtectSection("DataProtectionCo
nfigurationProvider");
config.Save(ConfigurationSaveMode.Modified);

ConfigurationManager.RefreshSection("connectionStrings");


foreach (ConnectionStringSettings connstr in
ConfigurationManager.ConnectionStrings)
{
Console.WriteLine("name: {0}, connstring: {1}",
connstr.Name, connstr.ConnectionString);
}

}
===========================================


========test code 2===============
static void ErrorTest2()
{

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

ConnectionStringsSection connstrs =
config.GetSection("connectionStrings") as ConnectionStringsSection;

foreach (ConnectionStringSettings connstr in
connstrs.ConnectionStrings)
{
Console.WriteLine(connstr.Name + "+" +
connstr.ConnectionString);
}


connstrs.SectionInformation.ForceSave = true;

connstrs.SectionInformation.ProtectSection("DataProtectionConfigurationProvi
der");
config.Save(ConfigurationSaveMode.Modified);

ConfigurationManager.RefreshSection("connectionStrings");

connstrs.ConnectionStrings.Add(new
ConnectionStringSettings("newconnstr1", "value"));
config.Save(ConfigurationSaveMode.Modified);

ConfigurationManager.RefreshSection("connectionStrings");


foreach (ConnectionStringSettings connstr in
connstrs.ConnectionStrings)
{
Console.WriteLine(connstr.Name + "+" +
connstr.ConnectionString);
}
}
=======================================

Please feel free to let me know if you have any other finding.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



This posting is provided "AS IS" with no warranties, and confers no rights.
 
C

cranley

I can confirm that the code you provided throws exception where you
specified. I would imagine, however, that it's not so much the
ConfigurationManager.ConnectionStrings that's not working, but rather
ConfigurationManager.GetSection() that has the bug (as it is using the
GetSection() method where I'm experiencing the error).

I would assume the ConnectionSTrings property on the
ConfigurationManager simply wraps around a call to GetSection()?

- ryan.
 
S

Steven Cheng[MSFT]

Thanks for your reply Rayn,

So you got the same test results as mine (test code 1 through error while
test code 2 works), correct?

Yes, I agree that the problem is not specific to ConfigurationManager, it
is the GetSection function and its callee (from call stack it is a
recursive fuction which throw the error).

Sure, the ConfigurationManager.ConnectionStrings static member also wrapper
the "GetSection" method. However, the problem here is that the test result
here indicate that the exception somewhat depend on the approach we get the
Section.

Anyway, I'll perform some further test through custom section since that
won't rely on any built-in static properties. I'll update you my test
results.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

Steven Cheng[MSFT]

Hello Rayn,

After some further tests, it seems the problem does not occur when I access
the ConfigurationSection through Configuration.GetSection instead of the
static members. I've created a custom configuration section class and use
the following code to test:

#"Myhandler" is my custom configuration section class

=================================
static void ErrorTest3()
{
Configuration config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);



MyHandler handler = config.GetSection("myCustomSection") as
MyHandler;


Console.WriteLine("handler.MyAttrib1:
{0}\r\nhandler.MyChildSection.MyChildAttribute1: {1}", handler.MyAttrib1,
handler.MyChildSection.MyChildAttribute1);


handler.SectionInformation.ForceSave = true;

handler.SectionInformation.ProtectSection("DataProtectionConfigurationProvid
er");
config.Save(ConfigurationSaveMode.Modified);

ConfigurationManager.RefreshSection("myCustomSection");


handler.MyAttrib1 = "new attribute 1";


config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("connectionStrings");




Console.WriteLine("handler.MyAttrib1:
{0}\r\nhandler.MyChildSection.MyChildAttribute1: {1}", handler.MyAttrib1,
handler.MyChildSection.MyChildAttribute1);

}
==========================

The above test can passed without any problem(no matter on initial run or
sequential runs). Is this also the same behavior on your side? If so, it
seems there is some problems concerned to the static member's
initialization code though it also use "GetSection". So far, due to the
limitation of newsgroup support interface, I would suggest you contact CSS
if you feel it necessary to get a instant resolution or hotfix on this:

http://support.microsoft.com/

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
C

cranley

Steven,

Thanks for the reply. While what you write is true, it's a workaround
which we cannot use in our library as our library grabs connection
strings both for windows and web applications. Thuse,
OpenExeConfiguration does not work in the Web world (as I was just
informed 5 minutes ago by one of my developers).

Is there any status update as to whether or not this was a previously
known bug in ConfigurationManager?

Thanks.

- ryan.
 
S

Steven Cheng[MSFT]

Hi Ryan,

I did have checked our internal database and this issue has been recorded
so far. I would suggest you submit this issue on your public product
feedback site:

http://connect.microsoft.com/feedback/default.aspx?SiteID=210

However, I think it'll be hard to address it in a short time. If you would
like to get a hotfix, you can contact CSS product support for assistance.

BTW, since you mentioned that the library will be used for both desktop and
ASP.NET applications, you can consider use the HttpContext.Current property
detect whether the application is under ASP.NET runtime context or another
workaround maybe design two separate methods for processing ASP.NET and
desktop application cases.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



==================================================

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.



Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.

==================================================



This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top