* Rename Umbraco.Core namespace to Umbraco.Cms.Core * Move extension methods in core project to Umbraco.Extensions * Move extension methods in core project to Umbraco.Extensions * Rename Umbraco.Examine namespace to Umbraco.Cms.Examine * Move examine extensions to Umbraco.Extensions namespace * Reflect changed namespaces in Builder and fix unit tests * Adjust namespace in Umbraco.ModelsBuilder.Embedded * Adjust namespace in Umbraco.Persistence.SqlCe * Adjust namespace in Umbraco.PublishedCache.NuCache * Align namespaces in Umbraco.Web.BackOffice * Align namespaces in Umbraco.Web.Common * Ensure that SqlCeSupport is still enabled after changing the namespace * Align namespaces in Umbraco.Web.Website * Align namespaces in Umbraco.Web.UI.NetCore * Align namespaces in Umbraco.Tests.Common * Align namespaces in Umbraco.Tests.UnitTests * Align namespaces in Umbraco.Tests.Integration * Fix errors caused by changed namespaces * Fix integration tests * Undo the Umbraco.Examine.Lucene namespace change This breaks integration tests on linux, since the namespace wont exists there because it's only used on windows. * Fix merge * Fix Merge
133 lines
5.3 KiB
C#
133 lines
5.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Web;
|
|
using Microsoft.AspNetCore.DataProtection;
|
|
using Microsoft.Extensions.Logging;
|
|
using Umbraco.Cms.Core;
|
|
using Umbraco.Cms.Web.Common.Constants;
|
|
using Umbraco.Extensions;
|
|
|
|
namespace Umbraco.Cms.Web.Common.Security
|
|
{
|
|
public class EncryptionHelper
|
|
{
|
|
// TODO: Decide if these belong here... I don't think so since this all has to do with surface controller routes
|
|
// could also just be injected too....
|
|
|
|
private static IDataProtector CreateDataProtector(IDataProtectionProvider dataProtectionProvider)
|
|
=> dataProtectionProvider.CreateProtector(nameof(EncryptionHelper));
|
|
|
|
public static string Decrypt(string encryptedString, IDataProtectionProvider dataProtectionProvider)
|
|
=> CreateDataProtector(dataProtectionProvider).Unprotect(encryptedString);
|
|
|
|
public static string Encrypt(string plainString, IDataProtectionProvider dataProtectionProvider)
|
|
=> CreateDataProtector(dataProtectionProvider).Protect(plainString);
|
|
|
|
/// <summary>
|
|
/// This is used in methods like BeginUmbracoForm and SurfaceAction to generate an encrypted string which gets submitted in a request for which
|
|
/// Umbraco can decrypt during the routing process in order to delegate the request to a specific MVC Controller.
|
|
/// </summary>
|
|
public static string CreateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string controllerName, string controllerAction, string area, object additionalRouteVals = null)
|
|
{
|
|
if (dataProtectionProvider is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(dataProtectionProvider));
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(controllerName))
|
|
{
|
|
throw new ArgumentException($"'{nameof(controllerName)}' cannot be null or empty.", nameof(controllerName));
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(controllerAction))
|
|
{
|
|
throw new ArgumentException($"'{nameof(controllerAction)}' cannot be null or empty.", nameof(controllerAction));
|
|
}
|
|
|
|
if (area is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(area));
|
|
}
|
|
|
|
// need to create a params string as Base64 to put into our hidden field to use during the routes
|
|
var surfaceRouteParams = $"{ViewConstants.ReservedAdditionalKeys.Controller}={WebUtility.UrlEncode(controllerName)}&{ViewConstants.ReservedAdditionalKeys.Action}={WebUtility.UrlEncode(controllerAction)}&{ViewConstants.ReservedAdditionalKeys.Area}={area}";
|
|
|
|
// checking if the additional route values is already a dictionary and convert to querystring
|
|
string additionalRouteValsAsQuery;
|
|
if (additionalRouteVals != null)
|
|
{
|
|
if (additionalRouteVals is Dictionary<string, object> additionalRouteValsAsDictionary)
|
|
{
|
|
additionalRouteValsAsQuery = additionalRouteValsAsDictionary.ToQueryString();
|
|
}
|
|
else
|
|
{
|
|
additionalRouteValsAsQuery = additionalRouteVals.ToDictionary<object>().ToQueryString();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
additionalRouteValsAsQuery = null;
|
|
}
|
|
|
|
if (additionalRouteValsAsQuery.IsNullOrWhiteSpace() == false)
|
|
{
|
|
surfaceRouteParams += "&" + additionalRouteValsAsQuery;
|
|
}
|
|
|
|
return Encrypt(surfaceRouteParams, dataProtectionProvider);
|
|
}
|
|
|
|
public static bool DecryptAndValidateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string encryptedString, out IDictionary<string, string> parts)
|
|
{
|
|
if (dataProtectionProvider == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(dataProtectionProvider));
|
|
}
|
|
|
|
string decryptedString;
|
|
try
|
|
{
|
|
decryptedString = Decrypt(encryptedString, dataProtectionProvider);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
StaticApplicationLogging.Logger.LogWarning("A value was detected in the ufprt parameter but Umbraco could not decrypt the string");
|
|
parts = null;
|
|
return false;
|
|
}
|
|
|
|
NameValueCollection parsedQueryString = HttpUtility.ParseQueryString(decryptedString);
|
|
parts = new Dictionary<string, string>();
|
|
foreach (var key in parsedQueryString.AllKeys)
|
|
{
|
|
parts[key] = parsedQueryString[key];
|
|
}
|
|
|
|
// validate all required keys exist
|
|
// the controller
|
|
if (parts.All(x => x.Key != ViewConstants.ReservedAdditionalKeys.Controller))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// the action
|
|
if (parts.All(x => x.Key != ViewConstants.ReservedAdditionalKeys.Action))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// the area
|
|
if (parts.All(x => x.Key != ViewConstants.ReservedAdditionalKeys.Area))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|