We are storing session data in the database, ideally each developer wants a session database on their own pcs, or possibly 1 developer might use inproc, another a mssql connection, another Oracle (if we get it working)
Is this possible? Can you access the session key in code and change it in the application startup? Or is there a file which could be merged with the web.config file that wouldn't get checked in?
Or option C which is easier but which I haven't thought of :-)
thanks
(Edit) Just found this which goes into this in some detail
developer specific app.config/web.config files in Visual Studio
(Answer). This came from a mix of Andrew Barber in the comments and the above
(1) In the web.config have this
<sessionState configSource="SystemWeb.config" />
(2) Make a file called SystemWebDefault.config which holds something like this:
<sessionState mode="SQLServer" allowCustomSqlDatabase="true" etc
(3) Each developer has to copy the default into a file called SystemWeb.config, changing it to suit themselves. This file should be explicitly ignored in subversion or whatever source control system you use.
(4) The build box needs a copy step
Something that might do what you want is NConfig (NuGet link). I've used it on projects to let multiple developers in our team have different connection strings for their local DB copies. It lets you define a machine specific config file to replace your default config values. For example you can define a {MachineName}.Custom.config that might look like this:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="main" connectionString="data source=(local)\SQLExpress;uid=username;pwd=password;initial catalog=mydb" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
I've never tried it with the session settings, but I can't find anything that says it won't work.
Related
Is there a way to get a web.config transformation in Visual Studio 2015+ to include the contents of an externally-referenced secrets file as described here?
This works well when developing locally, and doesn't include the file in source control, but when I go to deploy the web app to the server, I want it to include the username and password for another web service which it connects to. If I enter the settings manually in IIS on the server, they are lost each time I publish the app.
If I omit the keys in the appSettings block in my web.config (so that they are only referred to in the secrets file), the manually-entered settings in IIS on the server are removed completely whenever I publish the app.
Being able to refer to certain things in an external file for the sake of better security and not checking in passwords to source control isn't turning out to be a very good idea IMHO because my deployment is now a nightmare. I don't want to manually enter the passwords in the web.config file on the server after every deployment.
I'd rather not look into encryption, either, because I would have to do that for each server I deploy to so that the relevant machine key is used for each web.config file.
I've only recently thought about removing this password from source control, in response to a recent push to improve security practises at work - which I well understand and agree with - but I can also see why security is so poorly considered because the life of the ordinary developer becomes extremely unpleasant if there the tools available don't make it easy.
Surely there's a way without resorting to encryption?
Thanks.
Without a CI system I think your best option is probably a pre/post build action that executes a script?
I'd suggest you replace the actual values with tokens for your sensitive web.config values (something unique/easy to find like MY_PRODUCT_DATABASE_PASSWORD etc). Your web.config can then be checked into source control safely.
In VS you can add a build action to run a custom powershell or exe to basically perform a find-and-replace on the tokens with actual values before you zip & deploy as normal.
Exactly how/where you store the real values and how the script works is up to you. you could easily find a file on your deployment machine or a row in some database based on data passed to the script/exe from vs or from data within web.config itself (or embedded as a comment in web.config even).
Here's details of the variables available from vs you could pass to your exe or script in a build action: https://msdn.microsoft.com/en-us/library/42x5kfw4.aspx
It you wanted to use PowerShell you could read/replace/write values to a web.config(or any text file) like this answer: How can I replace every occurrence of a String in a file with PowerShell?
Following the Microsoft Docs example you've linked to, putting this XDT transformation inside Web.Release.config should do the trick:
<appSettings file="..\..\AppSettingsSecrets.config" xdt:Transform="SetAttributes">
<add key="mailAccount" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="mailPassword" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="TwilioSid" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="TwilioToken" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="TwilioFromPhone" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="GoogClientID" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="GoogClientSecret" xdt:Locator="Match(key)" xdt:Transform="Remove" />
</appSettings>
You dont need xdt:Locator attribute on <appSettings> element itself, because there is only one appSettings.
Edit: I've misunderstood the original question. The goal is to include contents of referenced file, which is not possible using XDT. There has to be another way.
I have an ASP.NET MVC5 website in development which I will shortly need to deploy to an IIS8 webserver. I'm trying to get the security model for the web.config file right, and in particular I want to:
Prevent secrets in the web.config file being exposed in my source control system
Protect the deployed web.config from prying eyes (I don't own the server).
From searching on SO and other sites I can see that there are specific tools/techniques to address each scenario:
'Included' sections in web.config that do not get saved to the SCCS.
Encrypted web.config files. Or encrypted sections of the file to be more precise.
I'm fine with both of those, but I can not for the life of me see how to combine the two techniques to solve both problems simultaneously. Is it possible to encrypt an external section? Is this even the right approach given that many of the answers are several years old now and address older versions of ASP.NET/MVC.
I can't be the first do want to do this so I'm sure I'm missing something obvious.
It has been suggested that this might already be answered here, however that question is about encrypting sections in the main web.config file, and I am asking about encrypting external sections. By that I mean sections that are 'included' using the configSource XML attribute.
It's probably bad form to answer ones own question, but I had a flash of inspiration and after a couple of hours of experimentation I have it working how I want.
The bit I had got all wrong was that I was trying to encrypt the external files. It does not work like that. Here's how it does work, at least, this is how it works for me on an IIS8.5 and ASP.NET v4.0.30319 server.
ConnectionStrings
Create the connectionStrings section in a separate file, e.g. Web.connectionStrings.config:
<?xml version="1.0"?>
<connectionStrings>
<add name="MyConnection" connectionString="{your connection string here}"
providerName="System.Data.SqlClient" />
</connectionStrings>
Ref this file from web.config:
<connectionStrings configSource="Web.connectionStrings.config" />
Make sure the external file is not under source code control so it does not get uploaded to your SCCS.
Deploy BOTH files, either as part of your deployment process or deploy the secure file manually if you're really paranoid.
Encrypt the connectionStrings section of the web.config normally, using the aspnet_regiis.exe command mentioned in the article mentioned by Afzaal. This process actually encrypts the contents of the Web.connectionStrings.config file and leaves the web.config file unchanged. You need to leave the external file in place but as it is now encrypted this is quite safe.
appSettings
Create your security-critical settings in a separate file, e.g. Web.appSettings.config.
<?xml version="1.0"?>
<appSettings>
<add key="wc1" value="web.app.config1" />
<add key="wc2" value="web.app.config2" />
</appSettings>
Ref this file from web.config:
<appSettings file="Web.App.config">
{other non-secure appSettings}
</appSettings>
Again, ensure the secure file is not under source control, and deploy both files to the production server.
Encrypt the appSettings section of the web.config file.
Unlike the connectionStrings section, this does not alter the external file at all. Instead, settings from both web.config and the external file are merged (external file takes precedence if duplicate keys are encountered) and are stored in an encrypted form in web.config.
At this point you can remove the Web.appSettings.config file as its contents are now incorporated into the main file.
Points to note:
If you introduce another Web.appSettings.config file at a later time, and restart the site, the contents of that file will override the encrypted settings in web.config. This may or may not be useful. When you remove the file and restart the site, the settings revert to the encrypted ones again.
If you decrypt the appSettings section, ALL the current settings are written back into the main web.config file, including those that originally came from the external file. You'll need to remember to remove them if you're just changing a setting and then re-encrypting the file again.
I have a WebForms project that has a connection string hard coded into the web.config (for Debug - web.Debug.config). This connection string points to a DB server for development.
I'd like to run a local copy of that database so that my changes don't immediately affect others.
What I've been doing is going into the web.config and updating the connection string to point to my local DB. This works, but is somewhat tedious as I have to remember to exclude the web.config and have to re-update it if I undo all changes.
Since, like I said, others are using this solution, I'd like to avoid checking anything in or modifying the web config.
Is there any way to override the web.config connection string to force the site to point to my local DB without checking anything in to source control?
One solution would be to use config transformation feature.
VS 2012:
Go to Build->Configuration Manager
Click on the Active solutions configuration List box and select "New".
Enter local as name of your new configuration and click Save.
Make sure you change the values under Configuration column back to Debug or which
ever was default previously
Right click on your Web.config file and select Add Config Transform, which will add the newly created web.local.config
Inside web.local.config add the local connection string transform, something like
<connectionStrings>
<add name="DbConnection"
connectionString="...Add Local Connection String..."
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
When you run or debug the project, make sure you select local configuration from the list box next to green run arrow. You just don't check in the web.local.config
One thing you might be able to do is have a separate file for your connection strings - you wouldn't check this into source control at all.
Depending on how your stuff is organized, you might need everyone who's doing development to do the same thing, and depending on how you do your publish/deploy, this may not work for you.
For example:
Web.config
<configuration>
<connectionStrings configSource="connectionstrings.config">
</connectionStrings>
</configuration>
connectionstrings.config (not in source control)
<connectionStrings>
<add name="cs" connectionString="server=.;database=whatever;"/>
</connectionStrings>
Each developer can choose which database their local machine points to, and as long as the connectionstrings.config file is not in source control (add it to the ignore list), nobody will step on each other's feet.
Create a SQL ALIAS on your local machine.
Click start run and type "cliconfg.exe" on local machine. This will help you to create a SQL Alias on your local machine. On the web.config connect to the live database but on your machine create a SQL Alias that will redirect to your local database. When this is done, when you publish the program it will automactically connect to the live database but when running from your local machine it will connect to local database without any code change.
I'm entering a parallel test and dev stage where I need to use one db for test and a different one for dev. How can I have the app choose which connection string to implement based on which physical folder it (the app) sits in?
I know there are SVN strategies to consider but this is small-scale enough to avoid 2 sperate code-bases. Would like to be able to publish the same VS project to either of my 2 directories without having to remind myself to change the connection string.
I'm running under IIS7 so perhaps it offers better control than conditionals in (and overrides) web.config. (or not)
thankx!
A word of advice:
I wouldn't base your connection string on your published folder. Down the road, the folder might change, and folks may not be aware that that determines which connection string you're using.
Instead, control it with a setting in your web.config file. Just add a setting that allows you to switch between production and dev databases. In fact, you could simply test for the presence of a debug mode setting. If that setting is there, you're targeting the development database; otherwise, you're targeting production.
The nice thing about that solution is that it doesn't depend on where you deploy the site, and you can document the setting in the Web.config file.
Hope this helps.
Edit for Clarity: By "a debug mode setting" I mean a setting that determines which database you're targeting, dev/production. Not whether your application is running in Debug mode, since the Framework already provides a function that does that. Also, you wouldn't necessarily remove the setting, since you'd want to keep it for documentation purposes. Rather, you'd comment it out.
You could e.g. create a <connectionStrings> container that contains a connection string for each folder your app could be in:
<connectionStrings>
<add name="Folder1" connectionString=".....(conn str. #1)...:" />
<add name="Folder2" connectionString=".....(conn str. #2)...:" />
....
<add name="Folder-n" connectionString=".....(conn str. #n)...:" />
</connectionStrings>
and then just pick the right one, depending on where your app starts up from.
Marc
Get a unique string for the application, perhaps something like:
string folder = Regex.Match(Server.MapPath("~"), #"\(.+?)\$").Groups[0].Value;
Then use the string to get a value from the web.config:
ConnectionStringSetting connectionString = ConfigurationManager.ConnectionStrings["ConnectionString." + folder] ?? ConfigurationManager.ConnectionStrings["ConnectionString"];
In the web.config you can add several connection strings with the folder names appended for each dev site, and a default connection string with just the name and no folder.
I usually put the connection strings into a separate config file and reference them from the main web.config using configSource:
In web.config:
<?xml version="1.0"?>
<configuration>
<!-- connection strings are located in an external config
file to facilitate deployment in various environments -->
<connectionStrings configSource="connections.config"></connectionStrings>
</configuration>
In connections.config:
<?xml version="1.0"?>
<connectionStrings>
<add name="ConnectionName" connectionString="[your connection string]"/>
</connectionStrings>
Once deployed, I usually exclude connections.config from future deployments (unless it should be changed, that is).
On a project I'm working on we have a web application with three configuration files;
Web.Config
Web.Config.TestServer
Web.Config.LiveServer
When we release to the test server, Web.Config is renamed to Web.Config.Development and Web.Config.TestServer is renamed to Web.Config, making that configuration active for the application.
It is quite onerous keeping three very similar configuration files up to date, and this system is used across a number of applications which are part of this project; not just the website.
The differences in configuration are most commonly local directories or paths, URLs, IPs, port numbers, and email addresses.
I'm looking for a better way.
While your approach seems tedious, I find it to be the best approach.
I used to keep all of my configurations in a single web.config file, and simply had the "production" section commented out.
Shortly after this I had to do a "hybrid" test where my lookup data was coming from the production server, but the new data was being inserted into the test database. At that point I had to start piece-mealing what parts of the configuration block to comment/uncomment, and it became a nightmare.
Similarly, we have our server administrators do the actual migration from test to production, and most of them aren't fluent enough in .NET to know how to manage the web.config files. It is far easier for them to simply see a .test or .prod file and migrate the proper one up.
You could use something like a database to store all your configurations, but then you're running into another layer of abstraction and you have to manage that on top of things.
Once you get the knack or the template of how your two (or three) configuration files will be setup, it becomes a lot easier to manage them and you can have your test server configuration get modified for some unique testing without much hassle.
If you have a db server in the mix, you can create a table that has the config, the property name, and the property value in it, then all you have to do is change one value in the web.config, the config name (dev, test, prod).
If you have different dbs for each config, then the only thing that's different is the connection string.
Use Config Transformation and there is a blog here about it.
http://blogs.msdn.com/b/webdevtools/archive/2009/05/04/web-deployment-web-config-transformation.aspx
Basically you create targets named web.{build configuration}.config. In each target file you write your transformation where you can add, delete and modify nodes and attributes. Example could be
web.staging.configss
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="personalDB"
connectionString="Server=StagingBox; Database=personal; User Id=admin; password=StagingPersonalPassword"
providerName="System.Data.SqlClient" xdt:Transform="Replace" xdt:Locator="Match(name)" />
<add name="professionalDB"
connectionString="Server=StagingBox; Database=professional; User Id=professional; password=StagingProfessionalPassword"
providerName="System.Data.SqlClient" xdt:Transform="Replace" xdt:Locator="Match(name)"/>
</connectionStrings>
</configuration>
You then execute the transform by calling MSBuild {project file} /t:TransformWebConfig /p:Configuration=Staging