adding back the functionality to install a machine key during installation

This commit is contained in:
Shannon
2017-08-02 16:16:59 +10:00
parent e29ac4d17c
commit 150e2b12e8
8 changed files with 204 additions and 1 deletions

View File

@@ -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
{
/// <summary>
/// Used to generate a machine key
/// </summary>
internal class MachineKeyGenerator
{
/// <summary>
/// Generates the string to be stored in the web.config
/// </summary>
/// <returns></returns>
/// <remarks>
/// Machine key details are here: https://msdn.microsoft.com/en-us/library/vstudio/w8h3skw9%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396
/// </remarks>
public string GenerateConfigurationBlock()
{
var c = @"<machineKey validationKey=""{0}""
decryptionKey=""{1}""
validation=""HMACSHA256"" decryption=""AES""
/>";
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();
}
}
}

View File

@@ -666,6 +666,7 @@
<Compile Include="Security\IBackOfficeUserPasswordChecker.cs" />
<Compile Include="Security\IMembershipProviderPasswordHasher.cs" />
<Compile Include="Security\IUserAwarePasswordHasher.cs" />
<Compile Include="Security\MachineKeyGenerator.cs" />
<Compile Include="Security\MembershipProviderPasswordHasher.cs" />
<Compile Include="Security\EmailService.cs" />
<Compile Include="Security\MembershipProviderPasswordValidator.cs" />

View File

@@ -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();
};
});

View File

@@ -0,0 +1,23 @@
<div ng-controller="Umbraco.Installer.MachineKeyController">
<h1>Configure an ASP.Net Machine Key</h1>
<p>
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.
</p>
<form name="myForm" class="form-horizontal" novalidate ng-submit="continue();">
<div class="row">
<div class="control-group">
<div class="controls">
<input type="submit" value="Continue" class="btn btn-success" />
<button class="btn" ng-click="ignoreKey()">I don't want a custom Machine Key</button>
</div>
</div>
</div>
</form>
</div>

View File

@@ -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),

View File

@@ -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<bool?>
{
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 : ""; }
}
/// <summary>
/// Don't display the view or execute if a machine key already exists
/// </summary>
/// <returns></returns>
private bool HasMachineKey()
{
var section = (MachineKeySection)WebConfigurationManager.GetSection("system.web/machineKey");
return section.ElementInformation.Source != null;
}
/// <summary>
/// The step execution method
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
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;
}
}
}

View File

@@ -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<DatabaseConfigureStep>("An error occurred, reconfiguring...", ex);
//something went wrong, could not connect so probably need to reconfigure
return true;
}

View File

@@ -359,6 +359,7 @@
<Compile Include="HealthCheck\StatusResultType.cs" />
<Compile Include="HealthCheck\Checks\DataIntegrity\XmlDataIntegrityHealthCheck.cs" />
<Compile Include="IHttpContextAccessor.cs" />
<Compile Include="Install\InstallSteps\ConfigureMachineKey.cs" />
<Compile Include="Models\ContentEditing\AssignedContentPermissions.cs" />
<Compile Include="Models\ContentEditing\AssignedUserGroupPermissions.cs" />
<Compile Include="Models\ContentEditing\ContentRedirectUrl.cs" />