diff --git a/src/Umbraco.Core/Security/MachineKeyGenerator.cs b/src/Umbraco.Core/Security/MachineKeyGenerator.cs new file mode 100644 index 0000000000..9dd06f44bd --- /dev/null +++ b/src/Umbraco.Core/Security/MachineKeyGenerator.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Umbraco.Core.Security +{ + /// + /// Used to generate a machine key + /// + internal class MachineKeyGenerator + { + /// + /// Generates the string to be stored in the web.config + /// + /// + /// + /// Machine key details are here: https://msdn.microsoft.com/en-us/library/vstudio/w8h3skw9%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396 + /// + public string GenerateConfigurationBlock() + { + var c = @""; + + var Xxx = 3; + + return string.Format(c, GenerateAESDecryptionKey(), GenerateHMACSHA256ValidationKey()); + } + + public string GenerateHMACSHA256ValidationKey() + { + //See: https://msdn.microsoft.com/en-us/library/vstudio/w8h3skw9%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396 + //See: https://msdn.microsoft.com/en-us/library/ff649308.aspx?f=255&MSPPError=-2147217396 + /* + key value Specifies a manually assigned key. + The validationKey value must be manually set to a string of hexadecimal + characters to ensure consistent configuration across all servers in a Web farm. + The length of the key depends on the hash algorithm that is used: + + AES requires a 256-bit key (64 hexadecimal characters). + MD5 requires a 128-bit key (32 hexadecimal characters). + SHA1 requires a 160-bit key (40 hexadecimal characters). + 3DES requires a 192-bit key (48 hexadecimal characters). + HMACSHA256 requires a 256-bit key (64 hexadecimal characters) == DEFAULT + HMACSHA384 requires a 384-bit key (96 hexadecimal characters). + HMACSHA512 requires a 512-bit key (128 hexadecimal characters). + */ + + //64 in length = 256 bits + return GenerateKey(64); + } + + public string GenerateAESDecryptionKey() + { + //See: //See: https://msdn.microsoft.com/en-us/library/vstudio/w8h3skw9%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396 + /* + key value Specifies a manually assigned key. + The decryptionKey value must be manually set to a string of + hexadecimal characters to ensure consistent configuration across all servers in a Web farm. + The key should be 64 bits (16 hexadecimal characters) long for DES encryption, or 192 bits + (48 hexadecimal characters) long for 3DES. For AES, the key can be 128 bits (32 characters), + 192 bits (48 characters), or 256 bits (64 characters) long. + */ + + //64 in length = 256 bits + return GenerateKey(64); + } + + private string GenerateKey(int len = 64) + { + var buff = new byte[len / 2]; + var rng = new RNGCryptoServiceProvider(); + rng.GetBytes(buff); + var sb = new StringBuilder(len); + + for (int i = 0; i < buff.Length; i++) + sb.Append(string.Format("{0:X2}", buff[i])); + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 596c72b56a..43e94fce8e 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -666,6 +666,7 @@ + diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/machinekey.controller.js b/src/Umbraco.Web.UI.Client/src/installer/steps/machinekey.controller.js new file mode 100644 index 0000000000..bdcef63d95 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/machinekey.controller.js @@ -0,0 +1,14 @@ +angular.module("umbraco.install").controller("Umbraco.Installer.MachineKeyController", function ($scope, installerService) { + + + $scope.continue = function () { + installerService.status.current.model = true; + installerService.forward(); + }; + + $scope.ignoreKey = function () { + installerService.status.current.model = false; + installerService.forward(); + }; + +}); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/machinekey.html b/src/Umbraco.Web.UI.Client/src/installer/steps/machinekey.html new file mode 100644 index 0000000000..732c7c1d56 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/machinekey.html @@ -0,0 +1,23 @@ +
+

Configure an ASP.Net Machine Key

+

+ By default the installer will generate a custom ASP.Net Machine Key for your site and install it into your web.config file. + A Machine Key is used for hashing and encryption and it is recommended that you install a custom one into your site. + This ensures that your site is fully portable between environments that might have different Machine Key settings and that + your site by default will work with load balancing when installed between various server environments. +

+ +
+ +
+
+
+ + + +
+
+
+ +
+
\ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index 6c088365a1..a3069342fc 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -48,6 +48,7 @@ namespace Umbraco.Web.Install new MajorVersion7UpgradeReport(_umbContext.Application), new Version73FileCleanup(_umbContext.HttpContext, _umbContext.Application.ProfilingLogger.Logger), new DatabaseConfigureStep(_umbContext.Application), + new ConfigureMachineKey(_umbContext.Application), new DatabaseInstallStep(_umbContext.Application), new DatabaseUpgradeStep(_umbContext.Application), new StarterKitDownloadStep(_umbContext.Application, _umbContext.Security, _umbContext.HttpContext), diff --git a/src/Umbraco.Web/Install/InstallSteps/ConfigureMachineKey.cs b/src/Umbraco.Web/Install/InstallSteps/ConfigureMachineKey.cs new file mode 100644 index 0000000000..e4038df4ab --- /dev/null +++ b/src/Umbraco.Web/Install/InstallSteps/ConfigureMachineKey.cs @@ -0,0 +1,75 @@ +using System; +using System.Configuration; +using System.Linq; +using System.Web.Configuration; +using System.Xml.Linq; +using Umbraco.Core; +using Umbraco.Core.IO; +using Umbraco.Core.Security; +using Umbraco.Web.Install.Models; + +namespace Umbraco.Web.Install.InstallSteps +{ + [InstallSetupStep(InstallationType.NewInstall, + "ConfigureMachineKey", "machinekey", 2, + "Updating some security settings...", + PerformsAppRestart = true)] + internal class ConfigureMachineKey : InstallSetupStep + { + private readonly ApplicationContext _appContext; + + public ConfigureMachineKey(ApplicationContext appContext) + { + if (appContext == null) throw new ArgumentNullException("appContext"); + _appContext = appContext; + } + + public override string View + { + get { return HasMachineKey() == false ? base.View : ""; } + } + + /// + /// Don't display the view or execute if a machine key already exists + /// + /// + private bool HasMachineKey() + { + var section = (MachineKeySection)WebConfigurationManager.GetSection("system.web/machineKey"); + return section.ElementInformation.Source != null; + } + + /// + /// The step execution method + /// + /// + /// + public override InstallSetupResult Execute(bool? model) + { + if (model.HasValue && model.Value == false) return null; + + //install the machine key + var fileName = IOHelper.MapPath(string.Format("{0}/web.config", SystemDirectories.Root)); + var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); + + var systemWeb = xml.Root.DescendantsAndSelf("system.web").Single(); + + // Update appSetting if it exists, or else create a new appSetting for the given key and value + var machineKey = systemWeb.Descendants("machineKey").FirstOrDefault(); + if (machineKey != null) return null; + + var generator = new MachineKeyGenerator(); + var generatedSection = generator.GenerateConfigurationBlock(); + systemWeb.Add(XElement.Parse(generatedSection)); + + xml.Save(fileName, SaveOptions.DisableFormatting); + + return null; + } + + public override bool RequiresExecution(bool? model) + { + return HasMachineKey() == false; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs index ce28a26176..9f74596ca2 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Web.Install.Models; @@ -94,8 +95,9 @@ namespace Umbraco.Web.Install.InstallSteps result.DetermineInstalledVersion(); return false; } - catch (Exception) + catch (Exception ex) { + _applicationContext.ProfilingLogger.Logger.Error("An error occurred, reconfiguring...", ex); //something went wrong, could not connect so probably need to reconfigure return true; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 59d066093e..950e494e35 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -359,6 +359,7 @@ +