I want to adjust the machine keys dynamically in code during runtime, for an IIS hosted ASP.NET MVC 4 website.
The machine keys, encryption and validation keys as well as algorithms to use, are stored in a database. Instead of reading the values from the web.config
file, I want to inject those values during application startup and let the system use those instead.
Is there any way to accomplish that without having to change web.config
at all (to only change the in memory configuration)?
I have tried accessing the configuration section but it is marked as readonly and is also sealed, so I cannot override IsReadOnly()
. However, there is a setter
that is an indicator, to me, that there may be a way to potentially remove the readonly flag.
var configSection = (MachineKeySection)ConfigurationManager.GetSection("system.web/machineKey");
if (!configSection.IsReadOnly())
{
configSection.ValidationKey = _platformInfo.MachineKey.ValidationKey;
configSection.DecryptionKey = _platformInfo.MachineKey.EncryptionKey;
...
}
Is there any way to accomplish this? The only alternative I can see is to use a custom method like AppHarbor, however I would rather stick with the built in approach if it is possible at all.
In case someone asks why I want to do that, the reason is, this is for a large number of identical websites running in a webfarm. Hence, having non-auto-generated keys is a must (must be the same on each server). Also each website should be isolated and should not share the same keys. As all websites are identical in their physical representation, they share the same physical location. That is the reason the web.config file cannot contain application specific settings.
Edit: It would be very helpful to confirm, at least, if it is simply not possible. As said, one can use custom authentication and encryption methods which would avoid using the machine key settings altogether. Thanks.
It's ugly, but I was able to use reflection to temporarily remove the read-only bit from the config section, set the keys, then restore it:
var getter = typeof(MachineKeySection).GetMethod("GetApplicationConfig", BindingFlags.Static | BindingFlags.NonPublic);
var config = (MachineKeySection)getter.Invoke(null, Array.Empty<object>());
var readOnlyField = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
readOnlyField.SetValue(config, false);
config.DecryptionKey = myKeys.EncryptionKey;
config.ValidationKey = myKeys.ValidationKey;
readOnlyField.SetValue(config, true);