Csp: lua script, CspSettingsHelper, portalrename, dns change, domains array
This commit is contained in:
parent
443453d538
commit
b3afd051af
@ -118,17 +118,7 @@ public class Tenant : IMapFrom<DbTenant>
|
||||
baseHost = HostedRegion;
|
||||
}
|
||||
|
||||
string result;
|
||||
if (baseHost == "localhost" || Alias == "localhost")
|
||||
{
|
||||
//single tenant on local host
|
||||
Alias = "localhost";
|
||||
result = HostName;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = $"{Alias}.{baseHost}".TrimEnd('.').ToLowerInvariant();
|
||||
}
|
||||
var result = $"{Alias}.{baseHost}".TrimEnd('.').ToLowerInvariant();
|
||||
|
||||
if (!string.IsNullOrEmpty(MappedDomain) && allowMappedDomain)
|
||||
{
|
||||
|
@ -90,6 +90,31 @@ server {
|
||||
proxy_set_header Connection $proxy_connection;
|
||||
proxy_set_header Proxy "";
|
||||
|
||||
|
||||
set $csp "";
|
||||
access_by_lua '
|
||||
local key = string.format("csp:%s",ngx.var.host)
|
||||
local redis = require "resty.redis"
|
||||
local red = redis:new()
|
||||
local redis_host = "127.0.0.1"
|
||||
local redis_port = 6379
|
||||
|
||||
red:set_timeout(1000) -- 1 second
|
||||
|
||||
local ok, err = red:connect(redis_host, redis_port)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to connect to redis: ", err)
|
||||
end
|
||||
|
||||
local csp, err = red:hget(key, "data")
|
||||
|
||||
if csp == ngx.null then
|
||||
ngx.log(ngx.ERR, "failed to get redis key: ", err)
|
||||
else
|
||||
ngx.header.Content_Security_Policy = csp
|
||||
end
|
||||
';
|
||||
|
||||
location ~* ^/ds-vpath/ {
|
||||
rewrite /ds-vpath/(.*) /$1 break;
|
||||
|
||||
|
@ -40,7 +40,6 @@ public class PortalController : ControllerBase
|
||||
private readonly CommonLinkUtility _commonLinkUtility;
|
||||
private readonly UrlShortener _urlShortener;
|
||||
private readonly AuthContext _authContext;
|
||||
private readonly WebItemSecurity _webItemSecurity;
|
||||
protected readonly SecurityContext _securityContext;
|
||||
private readonly SettingsManager _settingsManager;
|
||||
private readonly IMobileAppInstallRegistrator _mobileAppInstallRegistrator;
|
||||
@ -65,6 +64,7 @@ public class PortalController : ControllerBase
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly QuotaHelper _quotaHelper;
|
||||
private readonly CspSettingsHelper _cspSettingsHelper;
|
||||
|
||||
public PortalController(
|
||||
ILogger<PortalController> logger,
|
||||
@ -75,7 +75,6 @@ public class PortalController : ControllerBase
|
||||
CommonLinkUtility commonLinkUtility,
|
||||
UrlShortener urlShortener,
|
||||
AuthContext authContext,
|
||||
WebItemSecurity webItemSecurity,
|
||||
SecurityContext securityContext,
|
||||
SettingsManager settingsManager,
|
||||
IMobileAppInstallRegistrator mobileAppInstallRegistrator,
|
||||
@ -98,7 +97,8 @@ public class PortalController : ControllerBase
|
||||
TfaAppAuthSettingsHelper tfaAppAuthSettingsHelper,
|
||||
IMapper mapper,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
QuotaHelper quotaHelper)
|
||||
QuotaHelper quotaHelper,
|
||||
CspSettingsHelper cspSettingsHelper)
|
||||
{
|
||||
_log = logger;
|
||||
_apiContext = apiContext;
|
||||
@ -108,7 +108,6 @@ public class PortalController : ControllerBase
|
||||
_commonLinkUtility = commonLinkUtility;
|
||||
_urlShortener = urlShortener;
|
||||
_authContext = authContext;
|
||||
_webItemSecurity = webItemSecurity;
|
||||
_securityContext = securityContext;
|
||||
_settingsManager = settingsManager;
|
||||
_mobileAppInstallRegistrator = mobileAppInstallRegistrator;
|
||||
@ -132,6 +131,7 @@ public class PortalController : ControllerBase
|
||||
_mapper = mapper;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_quotaHelper = quotaHelper;
|
||||
_cspSettingsHelper = cspSettingsHelper;
|
||||
}
|
||||
|
||||
[AllowNotPayment]
|
||||
@ -370,10 +370,13 @@ public class PortalController : ControllerBase
|
||||
await _apiSystemHelper.AddTenantToCacheAsync(newAlias, user.Id);
|
||||
}
|
||||
|
||||
var oldDomain = tenant.GetTenantDomain(_coreSettings);
|
||||
tenant.Alias = alias;
|
||||
tenant = _tenantManager.SaveTenant(tenant);
|
||||
_tenantManager.SetCurrentTenant(tenant);
|
||||
|
||||
await _cspSettingsHelper.RenameDomain(oldDomain, tenant.GetTenantDomain(_coreSettings));
|
||||
|
||||
if (!string.IsNullOrEmpty(_apiSystemHelper.ApiCacheUrl))
|
||||
{
|
||||
await _apiSystemHelper.RemoveTenantFromCacheAsync(oldAlias, user.Id);
|
||||
|
@ -24,12 +24,6 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using Joonasw.AspNetCore.SecurityHeaders.Csp.Builder;
|
||||
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using AuditEventDto = ASC.Web.Api.ApiModel.ResponseDto.AuditEventDto;
|
||||
using LoginEventDto = ASC.Web.Api.ApiModel.ResponseDto.LoginEventDto;
|
||||
|
||||
@ -50,9 +44,8 @@ public class SecurityController : ControllerBase
|
||||
private readonly SettingsManager _settingsManager;
|
||||
private readonly AuditActionMapper _auditActionMapper;
|
||||
private readonly CoreBaseSettings _coreBaseSettings;
|
||||
private readonly CoreSettings _coreSettings;
|
||||
private readonly ApiContext _apiContext;
|
||||
private readonly IDistributedCache _distributedCache;
|
||||
private readonly CspSettingsHelper _cspSettingsHelper;
|
||||
|
||||
public SecurityController(
|
||||
PermissionContext permissionContext,
|
||||
@ -66,8 +59,7 @@ public class SecurityController : ControllerBase
|
||||
AuditActionMapper auditActionMapper,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
ApiContext apiContext,
|
||||
IDistributedCache distributedCache,
|
||||
CoreSettings coreSettings)
|
||||
CspSettingsHelper cspSettingsHelper)
|
||||
{
|
||||
_permissionContext = permissionContext;
|
||||
_tenantManager = tenantManager;
|
||||
@ -80,8 +72,7 @@ public class SecurityController : ControllerBase
|
||||
_auditActionMapper = auditActionMapper;
|
||||
_coreBaseSettings = coreBaseSettings;
|
||||
_apiContext = apiContext;
|
||||
_distributedCache = distributedCache;
|
||||
_coreSettings = coreSettings;
|
||||
_cspSettingsHelper = cspSettingsHelper;
|
||||
}
|
||||
|
||||
[HttpGet("audit/login/last")]
|
||||
@ -280,41 +271,17 @@ public class SecurityController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpPost("csp")]
|
||||
public object Csp(CspRequestsDto request)
|
||||
public async Task<object> Csp(CspRequestsDto request)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
ArgumentNullException.ThrowIfNull(request.Domain, nameof(request.Domain));
|
||||
|
||||
var domain = request.Domain;
|
||||
var csp = new CspBuilder();
|
||||
return await _cspSettingsHelper.Save(request.Domains);
|
||||
}
|
||||
|
||||
csp.ByDefaultAllow
|
||||
.FromSelf();
|
||||
|
||||
csp.AllowScripts
|
||||
.FromSelf()
|
||||
.From(domain);
|
||||
|
||||
csp.AllowStyles
|
||||
.FromSelf()
|
||||
.From(domain);
|
||||
|
||||
csp.AllowImages
|
||||
.FromSelf()
|
||||
.From(domain);
|
||||
|
||||
csp.AllowFraming
|
||||
.From(domain);
|
||||
|
||||
var (_, headerValue) = csp.BuildCspOptions().ToString(null);
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
|
||||
Serializer.Serialize(ms, headerValue);
|
||||
|
||||
_distributedCache.Set($"csp:{_tenantManager.GetCurrentTenant().GetTenantDomain(_coreSettings)}", Encoding.UTF8.GetBytes(headerValue));
|
||||
|
||||
return headerValue;
|
||||
[HttpGet("csp")]
|
||||
public CspSettings Csp()
|
||||
{
|
||||
return _cspSettingsHelper.Load();
|
||||
}
|
||||
|
||||
private void DemandAuditPermission()
|
||||
|
@ -325,9 +325,9 @@ public class SettingsController : BaseSettingsController
|
||||
}
|
||||
|
||||
[HttpPut("dns")]
|
||||
public object SaveDnsSettings(DnsSettingsRequestsDto model)
|
||||
public async Task<object> SaveDnsSettings(DnsSettingsRequestsDto model)
|
||||
{
|
||||
return _dnsSettings.SaveDnsSettings(model.DnsName, model.Enable);
|
||||
return await _dnsSettings.SaveDnsSettings(model.DnsName, model.Enable);
|
||||
}
|
||||
|
||||
[HttpGet("recalculatequota")]
|
||||
|
@ -28,5 +28,5 @@ namespace ASC.Web.Api.ApiModels.RequestsDto;
|
||||
|
||||
public class CspRequestsDto
|
||||
{
|
||||
public string Domain { get; set; }
|
||||
public IEnumerable<string> Domains { get; set; }
|
||||
}
|
||||
|
136
web/ASC.Web.Api/Core/CspSettings.cs
Normal file
136
web/ASC.Web.Api/Core/CspSettings.cs
Normal file
@ -0,0 +1,136 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.Web.Api.Core;
|
||||
|
||||
public class CspSettings : ISettings<CspSettings>
|
||||
{
|
||||
[JsonIgnore]
|
||||
public Guid ID => new Guid("27504162-16FF-405F-8530-1537B0F2B89D");
|
||||
|
||||
public IEnumerable<string> Domains { get; set; }
|
||||
|
||||
public CspSettings GetDefault()
|
||||
{
|
||||
return new CspSettings();
|
||||
}
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class CspSettingsHelper
|
||||
{
|
||||
private readonly SettingsManager _settingsManager;
|
||||
private readonly FilesLinkUtility _filesLinkUtility;
|
||||
private readonly TenantManager _tenantManager;
|
||||
private readonly CoreSettings _coreSettings;
|
||||
private readonly IDistributedCache _distributedCache;
|
||||
|
||||
public CspSettingsHelper(
|
||||
SettingsManager settingsManager,
|
||||
FilesLinkUtility filesLinkUtility,
|
||||
TenantManager tenantManager,
|
||||
CoreSettings coreSettings,
|
||||
IDistributedCache distributedCache)
|
||||
{
|
||||
_settingsManager = settingsManager;
|
||||
_filesLinkUtility = filesLinkUtility;
|
||||
_tenantManager = tenantManager;
|
||||
_coreSettings = coreSettings;
|
||||
_distributedCache = distributedCache;
|
||||
}
|
||||
|
||||
public async Task<string> Save(IEnumerable<string> domains)
|
||||
{
|
||||
var headerKey = GetKey(_tenantManager.GetCurrentTenant().GetTenantDomain(_coreSettings));
|
||||
var headerValue = "";
|
||||
|
||||
if (domains != null && domains.Any())
|
||||
{
|
||||
var csp = new CspBuilder();
|
||||
|
||||
csp.ByDefaultAllow
|
||||
.FromSelf()
|
||||
.From(_filesLinkUtility.DocServiceUrl);
|
||||
|
||||
var scriptBuilder = csp.AllowScripts
|
||||
.FromSelf()
|
||||
.From(_filesLinkUtility.DocServiceUrl)
|
||||
.AllowUnsafeInline();
|
||||
|
||||
var styleBuilder = csp.AllowStyles
|
||||
.FromSelf()
|
||||
.AllowUnsafeInline();
|
||||
|
||||
var imageBuilder = csp.AllowImages
|
||||
.FromSelf();
|
||||
|
||||
var frameBuilder = csp.AllowFraming;
|
||||
|
||||
foreach (var domain in domains)
|
||||
{
|
||||
scriptBuilder.From(domain);
|
||||
styleBuilder.From(domain);
|
||||
imageBuilder.From(domain);
|
||||
frameBuilder.From(domain);
|
||||
}
|
||||
|
||||
(_, headerValue) = csp.BuildCspOptions().ToString(null);
|
||||
|
||||
await _distributedCache.SetStringAsync(headerKey, headerValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _distributedCache.RemoveAsync(headerKey);
|
||||
}
|
||||
|
||||
var current = _settingsManager.Load<CspSettings>();
|
||||
current.Domains = domains;
|
||||
_settingsManager.Save(current);
|
||||
|
||||
return headerValue;
|
||||
}
|
||||
|
||||
public CspSettings Load()
|
||||
{
|
||||
return _settingsManager.Load<CspSettings>();
|
||||
}
|
||||
|
||||
public async Task RenameDomain(string oldDomain, string newDomain)
|
||||
{
|
||||
var oldKey = GetKey(oldDomain);
|
||||
var val = await _distributedCache.GetStringAsync(oldKey);
|
||||
if (!string.IsNullOrEmpty(val))
|
||||
{
|
||||
await _distributedCache.RemoveAsync(oldKey);
|
||||
await _distributedCache.SetStringAsync(GetKey(newDomain), val);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetKey(string domain)
|
||||
{
|
||||
return $"csp:{domain}";
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ public class DnsSettings
|
||||
private readonly StudioNotifyService _studioNotifyService;
|
||||
private readonly CommonLinkUtility _commonLinkUtility;
|
||||
private readonly MessageService _messageService;
|
||||
private readonly CspSettingsHelper _cspSettingsHelper;
|
||||
|
||||
public DnsSettings(
|
||||
PermissionContext permissionContext,
|
||||
@ -46,7 +47,8 @@ public class DnsSettings
|
||||
CoreSettings coreSettings,
|
||||
StudioNotifyService studioNotifyService,
|
||||
CommonLinkUtility commonLinkUtility,
|
||||
MessageService messageService)
|
||||
MessageService messageService,
|
||||
CspSettingsHelper cspSettingsHelper)
|
||||
{
|
||||
_permissionContext = permissionContext;
|
||||
_tenantManager = tenantManager;
|
||||
@ -56,9 +58,10 @@ public class DnsSettings
|
||||
_studioNotifyService = studioNotifyService;
|
||||
_commonLinkUtility = commonLinkUtility;
|
||||
_messageService = messageService;
|
||||
_cspSettingsHelper = cspSettingsHelper;
|
||||
}
|
||||
|
||||
public string SaveDnsSettings(string dnsName, bool enableDns)
|
||||
public async Task<string> SaveDnsSettings(string dnsName, bool enableDns)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -80,8 +83,12 @@ public class DnsSettings
|
||||
{
|
||||
if (_coreBaseSettings.Standalone)
|
||||
{
|
||||
var oldDomain = tenant.GetTenantDomain(_coreSettings);
|
||||
|
||||
tenant.MappedDomain = dnsName;
|
||||
_tenantManager.SaveTenant(tenant);
|
||||
|
||||
await _cspSettingsHelper.RenameDomain(oldDomain, tenant.GetTenantDomain(_coreSettings));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -145,17 +145,22 @@ global using AutoMapper;
|
||||
|
||||
global using Google.Authenticator;
|
||||
|
||||
global using Joonasw.AspNetCore.SecurityHeaders.Csp.Builder;
|
||||
|
||||
global using MailKit.Security;
|
||||
|
||||
global using Microsoft.AspNetCore.Authorization;
|
||||
global using Microsoft.AspNetCore.Mvc;
|
||||
global using Microsoft.EntityFrameworkCore;
|
||||
global using Microsoft.Extensions.Caching.Distributed;
|
||||
global using Microsoft.Extensions.Caching.Memory;
|
||||
global using Microsoft.Extensions.Hosting.WindowsServices;
|
||||
global using Microsoft.Extensions.Primitives;
|
||||
|
||||
global using MimeKit;
|
||||
|
||||
global using ProtoBuf;
|
||||
|
||||
global using static ASC.ActiveDirectory.Base.Settings.LdapSettings;
|
||||
global using static ASC.Security.Cryptography.EmailValidationKeyProvider;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user