V9: Allowlisting remote URLs for displaying content on the content dashboard (#11825)
* Fixing ContentDashboardSettings to work when set in the config * Moving file in Models folder and adding ContentDashboardUrlAllowlist setting * Implementing allowlist for content dashboard base url * Cleanup * Error msg vs log msg
This commit is contained in:
committed by
GitHub
parent
1b5830a9d7
commit
229ca989eb
@@ -86,6 +86,8 @@ namespace JsonSchema
|
||||
public PackageMigrationSettings PackageMigration { get; set; }
|
||||
|
||||
public LegacyPasswordMigrationSettings LegacyPasswordMigration { get; set; }
|
||||
|
||||
public ContentDashboardSettings ContentDashboard { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
|
||||
namespace Umbraco.Cms.Core.Configuration
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Umbraco.Cms.Core.Configuration.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Typed configuration options for content dashboard settings.
|
||||
/// </summary>
|
||||
[UmbracoOptions(Constants.Configuration.ConfigContentDashboard)]
|
||||
public class ContentDashboardSettings
|
||||
{
|
||||
private const string DefaultContentDashboardPath = "cms";
|
||||
@@ -18,6 +23,13 @@ namespace Umbraco.Cms.Core.Configuration
|
||||
/// Gets the path to use when constructing the URL for retrieving data for the content dashboard.
|
||||
/// </summary>
|
||||
/// <value>The URL path.</value>
|
||||
public string ContentDashboardPath { get; set; } = DefaultContentDashboardPath;
|
||||
[DefaultValue(DefaultContentDashboardPath)]
|
||||
public string ContentDashboardPath { get; set; } = DefaultContentDashboardPath;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the allowed addresses to retrieve data for the content dashboard.
|
||||
/// </summary>
|
||||
/// <value>The URLs.</value>
|
||||
public string[] ContentDashboardUrlAllowlist { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Cms.Core
|
||||
namespace Umbraco.Cms.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
@@ -54,6 +54,7 @@
|
||||
public const string ConfigUserPassword = ConfigPrefix + "Security:UserPassword";
|
||||
public const string ConfigRichTextEditor = ConfigPrefix + "RichTextEditor";
|
||||
public const string ConfigPackageMigration = ConfigPrefix + "PackageMigration";
|
||||
public const string ConfigContentDashboard = ConfigPrefix + "ContentDashboard";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,8 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
.AddUmbracoOptions<BasicAuthSettings>()
|
||||
.AddUmbracoOptions<RuntimeMinificationSettings>()
|
||||
.AddUmbracoOptions<LegacyPasswordMigrationSettings>()
|
||||
.AddUmbracoOptions<PackageMigrationSettings>();
|
||||
.AddUmbracoOptions<PackageMigrationSettings>()
|
||||
.AddUmbracoOptions<ContentDashboardSettings>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -8,9 +9,11 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Dashboards;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
@@ -40,7 +43,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
private readonly IDashboardService _dashboardService;
|
||||
private readonly IUmbracoVersion _umbracoVersion;
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
private readonly IOptions<ContentDashboardSettings> _dashboardSettings;
|
||||
private readonly ContentDashboardSettings _dashboardSettings;
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DashboardController"/> with all its dependencies.
|
||||
/// </summary>
|
||||
@@ -60,12 +63,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
_dashboardService = dashboardService;
|
||||
_umbracoVersion = umbracoVersion;
|
||||
_shortStringHelper = shortStringHelper;
|
||||
_dashboardSettings = dashboardSettings;
|
||||
_dashboardSettings = dashboardSettings.Value;
|
||||
}
|
||||
|
||||
//we have just one instance of HttpClient shared for the entire application
|
||||
private static readonly HttpClient HttpClient = new HttpClient();
|
||||
|
||||
// TODO(V10) : change return type to Task<ActionResult<JObject>> and consider removing baseUrl as parameter
|
||||
//we have baseurl as a param to make previewing easier, so we can test with a dev domain from client side
|
||||
[ValidateAngularAntiForgeryToken]
|
||||
public async Task<JObject> GetRemoteDashboardContent(string section, string baseUrl = "https://dashboard.umbraco.com/")
|
||||
@@ -76,9 +80,19 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var version = _umbracoVersion.SemanticVersion.ToSemanticStringWithoutBuild();
|
||||
var isAdmin = user.IsAdmin();
|
||||
|
||||
if (!IsAllowedUrl(baseUrl))
|
||||
{
|
||||
_logger.LogError($"The following URL is not listed in the setting 'Umbraco:CMS:ContentDashboard:ContentDashboardUrlAllowlist' in configuration: {baseUrl}");
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
|
||||
// Hacking the response - can't set the HttpContext.Response.Body, so instead returning the error as JSON
|
||||
var errorJson = JsonConvert.SerializeObject(new { Error = "Dashboard source not permitted" });
|
||||
return JObject.Parse(errorJson);
|
||||
}
|
||||
|
||||
var url = string.Format("{0}{1}?section={2}&allowed={3}&lang={4}&version={5}&admin={6}",
|
||||
baseUrl,
|
||||
_dashboardSettings.Value.ContentDashboardPath,
|
||||
_dashboardSettings.ContentDashboardPath,
|
||||
section,
|
||||
allowedSections,
|
||||
language,
|
||||
@@ -116,8 +130,15 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO(V10) : consider removing baseUrl as parameter
|
||||
public async Task<IActionResult> GetRemoteDashboardCss(string section, string baseUrl = "https://dashboard.umbraco.org/")
|
||||
{
|
||||
if (!IsAllowedUrl(baseUrl))
|
||||
{
|
||||
_logger.LogError($"The following URL is not listed in the setting 'Umbraco:CMS:ContentDashboard:ContentDashboardUrlAllowlist' in configuration: {baseUrl}");
|
||||
return BadRequest("Dashboard source not permitted");
|
||||
}
|
||||
|
||||
var url = string.Format(baseUrl + "css/dashboard.css?section={0}", section);
|
||||
var key = "umbraco-dynamic-dashboard-css-" + section;
|
||||
|
||||
@@ -152,12 +173,18 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
|
||||
|
||||
return Content(result,"text/css", Encoding.UTF8);
|
||||
return Content(result, "text/css", Encoding.UTF8);
|
||||
|
||||
}
|
||||
|
||||
public async Task<IActionResult> GetRemoteXml(string site, string url)
|
||||
{
|
||||
if (!IsAllowedUrl(url))
|
||||
{
|
||||
_logger.LogError($"The following URL is not listed in the setting 'Umbraco:CMS:ContentDashboard:ContentDashboardUrlAllowlist' in configuration: {url}");
|
||||
return BadRequest("Dashboard source not permitted");
|
||||
}
|
||||
|
||||
// This is used in place of the old feedproxy.config
|
||||
// Which was used to grab data from our.umbraco.com, umbraco.com or umbraco.tv
|
||||
// for certain dashboards or the help drawer
|
||||
@@ -214,7 +241,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
return Content(result,"text/xml", Encoding.UTF8);
|
||||
return Content(result, "text/xml", Encoding.UTF8);
|
||||
|
||||
}
|
||||
|
||||
@@ -240,5 +267,19 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
})
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
// Checks if the passed URL is part of the configured allowlist of addresses
|
||||
private bool IsAllowedUrl(string url)
|
||||
{
|
||||
// No addresses specified indicates that any URL is allowed
|
||||
if (_dashboardSettings.ContentDashboardUrlAllowlist is null || _dashboardSettings.ContentDashboardUrlAllowlist.Contains(url, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user