Files
Umbraco-CMS/src/Umbraco.Web.Common/Security/EncryptionHelper.cs
Mole bf41c2eeaa Netcore: Align namespaces (#9801)
* 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
2021-02-18 11:06:02 +01:00

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;
}
}
}