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