DocSpace-buildtools/web/ASC.Web.Core/WebItemSecurity.cs

431 lines
16 KiB
C#
Raw Normal View History

2022-03-15 18:00:53 +00:00
// (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
2019-06-07 08:59:07 +00:00
using SecurityAction = ASC.Common.Security.Authorizing.Action;
2022-03-17 15:13:38 +00:00
namespace ASC.Web.Core;
[Singletone]
public class WebItemSecurityCache
2019-06-07 08:59:07 +00:00
{
2022-04-15 09:08:06 +00:00
private readonly ICache _cache;
private readonly ICacheNotify<WebItemSecurityNotifier> _cacheNotify;
2019-10-11 15:03:03 +00:00
2022-03-17 15:13:38 +00:00
public WebItemSecurityCache(ICacheNotify<WebItemSecurityNotifier> cacheNotify, ICache cache)
{
2022-04-15 09:08:06 +00:00
_cache = cache;
_cacheNotify = cacheNotify;
_cacheNotify.Subscribe((r) =>
2019-10-11 15:03:03 +00:00
{
2022-03-17 15:13:38 +00:00
ClearCache(r.Tenant);
2022-04-15 09:08:06 +00:00
}, CacheNotifyAction.Any);
2022-03-17 15:13:38 +00:00
}
2019-10-11 15:03:03 +00:00
2022-03-17 15:13:38 +00:00
public void ClearCache(int tenantId)
{
2022-04-15 09:08:06 +00:00
_cache.Remove(GetCacheKey(tenantId));
2022-03-17 15:13:38 +00:00
}
2019-10-11 15:03:03 +00:00
2022-03-17 15:13:38 +00:00
public string GetCacheKey(int tenantId)
{
return $"{tenantId}:webitemsecurity";
}
2019-10-11 15:03:03 +00:00
2022-03-17 15:13:38 +00:00
public void Publish(int tenantId)
{
2022-04-15 09:08:06 +00:00
_cacheNotify.Publish(new WebItemSecurityNotifier { Tenant = tenantId }, CacheNotifyAction.Any);
2022-03-17 15:13:38 +00:00
}
2019-10-11 15:03:03 +00:00
2022-03-17 15:13:38 +00:00
public Dictionary<string, bool> Get(int tenantId)
{
2022-04-15 09:08:06 +00:00
return _cache.Get<Dictionary<string, bool>>(GetCacheKey(tenantId));
2022-03-17 15:13:38 +00:00
}
2020-09-30 14:47:42 +00:00
2022-03-17 15:13:38 +00:00
public Dictionary<string, bool> GetOrInsert(int tenantId)
{
var dic = Get(tenantId);
if (dic == null)
2019-10-11 15:03:03 +00:00
{
2022-03-17 15:13:38 +00:00
dic = new Dictionary<string, bool>();
2022-04-15 09:08:06 +00:00
_cache.Insert(GetCacheKey(tenantId), dic, DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)));
2022-03-17 15:13:38 +00:00
}
2019-10-11 15:03:03 +00:00
2022-03-17 15:13:38 +00:00
return dic;
}
}
2019-10-11 15:03:03 +00:00
2022-03-17 15:13:38 +00:00
[Scope]
public class WebItemSecurity
{
2022-03-17 16:57:02 +00:00
private static readonly SecurityAction _read = new SecurityAction(new Guid("77777777-32ae-425f-99b5-83176061d1ae"), "ReadWebItem", false, true);
2022-03-17 15:13:38 +00:00
2022-04-15 09:08:06 +00:00
private readonly UserManager _userManager;
private readonly AuthContext _authContext;
private readonly PermissionContext _permissionContext;
private readonly AuthManager _authentication;
private readonly WebItemManager _webItemManager;
private readonly TenantManager _tenantManager;
private readonly AuthorizationManager _authorizationManager;
private readonly CoreBaseSettings _coreBaseSettings;
private readonly WebItemSecurityCache _webItemSecurityCache;
private readonly SettingsManager _settingsManager;
2022-03-17 15:13:38 +00:00
public WebItemSecurity(
UserManager userManager,
AuthContext authContext,
PermissionContext permissionContext,
AuthManager authentication,
WebItemManager webItemManager,
TenantManager tenantManager,
AuthorizationManager authorizationManager,
CoreBaseSettings coreBaseSettings,
WebItemSecurityCache webItemSecurityCache,
SettingsManager settingsManager)
{
2022-04-15 09:08:06 +00:00
_userManager = userManager;
_authContext = authContext;
_permissionContext = permissionContext;
_authentication = authentication;
_webItemManager = webItemManager;
_tenantManager = tenantManager;
_authorizationManager = authorizationManager;
_coreBaseSettings = coreBaseSettings;
_webItemSecurityCache = webItemSecurityCache;
_settingsManager = settingsManager;
2019-10-11 15:03:03 +00:00
}
2022-03-17 15:13:38 +00:00
//
public bool IsAvailableForMe(Guid id)
2019-06-07 08:59:07 +00:00
{
2022-04-15 09:08:06 +00:00
return IsAvailableForUser(id, _authContext.CurrentAccount.ID);
2022-03-17 15:13:38 +00:00
}
2019-09-09 12:56:33 +00:00
2022-03-17 15:13:38 +00:00
public bool IsAvailableForUser(Guid itemId, Guid @for)
{
var id = itemId.ToString();
bool result;
2019-06-07 08:59:07 +00:00
2022-04-15 09:08:06 +00:00
var tenant = _tenantManager.GetCurrentTenant();
var dic = _webItemSecurityCache.GetOrInsert(tenant.Id);
2022-03-17 15:13:38 +00:00
if (dic != null)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
lock (dic)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
if (dic.TryGetValue(id + @for, out var value))
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
return value;
2019-06-07 08:59:07 +00:00
}
}
2022-03-17 15:13:38 +00:00
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
// can read or administrator
2022-04-15 09:08:06 +00:00
var securityObj = WebItemSecurityObject.Create(id, _webItemManager);
2019-06-07 08:59:07 +00:00
2022-04-15 09:08:06 +00:00
if (_coreBaseSettings.Personal
2022-03-17 15:13:38 +00:00
&& securityObj.WebItemId != WebItemManager.DocumentsProductID)
{
// only files visible in your-docs portal
result = false;
}
else
{
2022-04-15 09:08:06 +00:00
var webitem = _webItemManager[securityObj.WebItemId];
2022-03-17 15:13:38 +00:00
if (webitem != null)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
if ((webitem.ID == WebItemManager.CRMProductID ||
webitem.ID == WebItemManager.PeopleProductID ||
webitem.ID == WebItemManager.BirthdaysProductID ||
webitem.ID == WebItemManager.MailProductID) &&
2022-04-15 09:08:06 +00:00
_userManager.GetUsers(@for).IsVisitor(_userManager))
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
// hack: crm, people, birtthday and mail products not visible for collaborators
result = false;
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
else if ((webitem.ID == WebItemManager.CalendarProductID ||
webitem.ID == WebItemManager.TalkProductID) &&
2022-04-15 09:08:06 +00:00
_userManager.GetUsers(@for).IsOutsider(_userManager))
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
// hack: calendar and talk products not visible for outsider
2019-06-07 08:59:07 +00:00
result = false;
}
2022-03-17 15:13:38 +00:00
else if (webitem is IModule)
{
2022-04-15 09:08:06 +00:00
result = _permissionContext.PermissionResolver.Check(_authentication.GetAccountByID(tenant.Id, @for), securityObj, null, _read) &&
IsAvailableForUser(_webItemManager.GetParentItemID(webitem.ID), @for);
2022-03-17 15:13:38 +00:00
}
else
2019-06-07 08:59:07 +00:00
{
2022-04-15 09:08:06 +00:00
var hasUsers = _authorizationManager.GetAces(Guid.Empty, _read.ID, securityObj).Any(a => a.Subject != ASC.Core.Users.Constants.GroupEveryone.ID);
result = _permissionContext.PermissionResolver.Check(_authentication.GetAccountByID(tenant.Id, @for), securityObj, null, _read) ||
2022-03-17 15:13:38 +00:00
(hasUsers && IsProductAdministrator(securityObj.WebItemId, @for));
2019-06-07 08:59:07 +00:00
}
}
2022-03-17 15:13:38 +00:00
else
{
result = false;
}
2019-06-07 08:59:07 +00:00
}
2022-04-15 09:08:06 +00:00
dic = _webItemSecurityCache.Get(tenant.Id);
2022-03-17 15:13:38 +00:00
if (dic != null)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
lock (dic)
2022-03-17 15:01:39 +00:00
{
2022-03-17 15:13:38 +00:00
dic[id + @for] = result;
2022-03-17 15:01:39 +00:00
}
2022-03-17 15:13:38 +00:00
}
return result;
}
2019-08-15 12:04:42 +00:00
2022-03-17 15:13:38 +00:00
public void SetSecurity(string id, bool enabled, params Guid[] subjects)
{
2022-04-15 09:08:06 +00:00
if (_settingsManager.Load<TenantAccessSettings>().Anyone)
2022-03-17 15:13:38 +00:00
{
throw new SecurityException("Security settings are disabled for an open portal");
}
2019-06-07 08:59:07 +00:00
2022-04-15 09:08:06 +00:00
var securityObj = WebItemSecurityObject.Create(id, _webItemManager);
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
// remove old aces
2022-04-15 09:08:06 +00:00
_authorizationManager.RemoveAllAces(securityObj);
2022-03-17 16:57:02 +00:00
var allowToAll = new AzRecord(ASC.Core.Users.Constants.GroupEveryone.ID, _read.ID, AceType.Allow, securityObj.FullId);
2022-04-15 09:08:06 +00:00
_authorizationManager.RemoveAce(allowToAll);
2022-03-17 15:13:38 +00:00
// set new aces
if (subjects == null || subjects.Length == 0 || subjects.Contains(ASC.Core.Users.Constants.GroupEveryone.ID))
{
if (!enabled && subjects != null && subjects.Length == 0)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
// users from list with no users equals allow to all users
enabled = true;
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
subjects = new[] { ASC.Core.Users.Constants.GroupEveryone.ID };
}
foreach (var s in subjects)
{
2022-03-17 16:57:02 +00:00
var a = new AzRecord(s, _read.ID, enabled ? AceType.Allow : AceType.Deny, securityObj.FullId);
2022-04-15 09:08:06 +00:00
_authorizationManager.AddAce(a);
2019-06-07 08:59:07 +00:00
}
2022-04-15 09:08:06 +00:00
_webItemSecurityCache.Publish(_tenantManager.GetCurrentTenant().Id);
2022-03-17 15:13:38 +00:00
}
public WebItemSecurityInfo GetSecurityInfo(string id)
{
var info = GetSecurity(id).ToList();
2022-04-15 09:08:06 +00:00
var module = _webItemManager.GetParentItemID(new Guid(id)) != Guid.Empty;
2022-03-17 15:13:38 +00:00
return new WebItemSecurityInfo
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
WebItemId = id,
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
Enabled = info.Count == 0 || (!module && info.Any(i => i.Item2)) || (module && info.All(i => i.Item2)),
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
Users = info
2022-04-15 09:08:06 +00:00
.Select(i => _userManager.GetUsers(i.Item1))
2022-03-17 15:13:38 +00:00
.Where(u => u.Id != ASC.Core.Users.Constants.LostUser.Id),
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
Groups = info
2022-04-15 09:08:06 +00:00
.Select(i => _userManager.GetGroupInfo(i.Item1))
2022-03-17 15:13:38 +00:00
.Where(g => g.ID != ASC.Core.Users.Constants.LostGroupInfo.ID && g.CategoryID != ASC.Core.Users.Constants.SysGroupCategoryId)
};
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
private IEnumerable<Tuple<Guid, bool>> GetSecurity(string id)
{
2022-04-15 09:08:06 +00:00
var securityObj = WebItemSecurityObject.Create(id, _webItemManager);
var result = _authorizationManager
2022-03-17 16:57:02 +00:00
.GetAcesWithInherits(Guid.Empty, _read.ID, securityObj, null)
2022-03-17 15:13:38 +00:00
.GroupBy(a => a.Subject)
.Select(a => Tuple.Create(a.Key, a.First().AceType == AceType.Allow))
.ToList();
if (result.Count == 0)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
result.Add(Tuple.Create(ASC.Core.Users.Constants.GroupEveryone.ID, false));
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
return result;
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
public void SetProductAdministrator(Guid productid, Guid userid, bool administrator)
{
if (productid == Guid.Empty)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
productid = ASC.Core.Users.Constants.GroupAdmin.ID;
}
if (administrator)
{
2022-04-15 09:08:06 +00:00
if (_userManager.IsUserInGroup(userid, ASC.Core.Users.Constants.GroupVisitor.ID))
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
throw new SecurityException("Collaborator can not be an administrator");
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
if (productid == WebItemManager.PeopleProductID)
{
foreach (var ace in GetPeopleModuleActions(userid))
2019-06-07 08:59:07 +00:00
{
2022-04-15 09:08:06 +00:00
_authorizationManager.AddAce(ace);
2019-06-07 08:59:07 +00:00
}
}
2022-03-17 15:13:38 +00:00
2022-04-15 09:08:06 +00:00
_userManager.AddUserIntoGroup(userid, productid);
2022-03-17 15:13:38 +00:00
}
else
{
if (productid == ASC.Core.Users.Constants.GroupAdmin.ID)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
var groups = new List<Guid> { WebItemManager.MailProductID };
2022-04-15 09:08:06 +00:00
groups.AddRange(_webItemManager.GetItemsAll().OfType<IProduct>().Select(p => p.ID));
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
foreach (var id in groups)
{
2022-04-15 09:08:06 +00:00
_userManager.RemoveUserFromGroup(userid, id);
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
if (productid == ASC.Core.Users.Constants.GroupAdmin.ID || productid == WebItemManager.PeopleProductID)
{
foreach (var ace in GetPeopleModuleActions(userid))
2019-06-07 08:59:07 +00:00
{
2022-04-15 09:08:06 +00:00
_authorizationManager.RemoveAce(ace);
2019-06-07 08:59:07 +00:00
}
}
2022-04-15 09:08:06 +00:00
_userManager.RemoveUserFromGroup(userid, productid);
2019-06-07 08:59:07 +00:00
}
2022-04-15 09:08:06 +00:00
_webItemSecurityCache.Publish(_tenantManager.GetCurrentTenant().Id);
2022-03-17 15:13:38 +00:00
}
public bool IsProductAdministrator(Guid productid, Guid userid)
{
2022-04-15 09:08:06 +00:00
return _userManager.IsUserInGroup(userid, ASC.Core.Users.Constants.GroupAdmin.ID) ||
_userManager.IsUserInGroup(userid, productid);
2022-03-17 15:13:38 +00:00
}
public IEnumerable<UserInfo> GetProductAdministrators(Guid productid)
{
var groups = new List<Guid>();
if (productid == Guid.Empty)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
groups.Add(ASC.Core.Users.Constants.GroupAdmin.ID);
2022-04-15 09:08:06 +00:00
groups.AddRange(_webItemManager.GetItemsAll().OfType<IProduct>().Select(p => p.ID));
2022-03-17 15:13:38 +00:00
groups.Add(WebItemManager.MailProductID);
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
else
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
groups.Add(productid);
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
var users = Enumerable.Empty<UserInfo>();
foreach (var id in groups)
2019-06-07 08:59:07 +00:00
{
2022-04-15 09:08:06 +00:00
users = users.Union(_userManager.GetUsersByGroup(id));
2022-03-17 15:13:38 +00:00
}
return users.ToList();
}
private static IEnumerable<AzRecord> GetPeopleModuleActions(Guid userid)
{
return new List<Guid>
2019-06-07 08:59:07 +00:00
{
ASC.Core.Users.Constants.Action_AddRemoveUser.ID,
ASC.Core.Users.Constants.Action_EditUser.ID,
ASC.Core.Users.Constants.Action_EditGroups.ID
}.Select(action => new AzRecord(userid, action, AceType.Allow));
2022-03-17 15:13:38 +00:00
}
private class WebItemSecurityObject : ISecurityObject
{
public Guid WebItemId { get; private set; }
2022-04-15 09:08:06 +00:00
private readonly WebItemManager _webItemManager;
2022-03-17 15:13:38 +00:00
public Type ObjectType
{
get { return GetType(); }
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
public object SecurityId
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
get { return WebItemId.ToString("N"); }
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
public string FullId => AzObjectIdHelper.GetFullObjectId(this);
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
public bool InheritSupported
{
get { return true; }
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
public bool ObjectRolesSupported
{
get { return false; }
}
2022-02-28 09:06:06 +00:00
2022-03-17 15:13:38 +00:00
public static WebItemSecurityObject Create(string id, WebItemManager webItemManager)
{
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(id);
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
var itemId = Guid.Empty;
if (32 <= id.Length)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
itemId = new Guid(id);
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
else
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
var w = webItemManager
.GetItemsAll()
.FirstOrDefault(i => id.Equals(i.GetSysName(), StringComparison.InvariantCultureIgnoreCase));
if (w != null)
2019-06-07 08:59:07 +00:00
{
2022-03-17 15:13:38 +00:00
itemId = w.ID;
2019-06-07 08:59:07 +00:00
}
}
2022-03-17 15:13:38 +00:00
return new WebItemSecurityObject(itemId, webItemManager);
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
private WebItemSecurityObject(Guid itemId, WebItemManager webItemManager)
{
WebItemId = itemId;
2022-04-15 09:08:06 +00:00
_webItemManager = webItemManager;
2022-03-17 15:13:38 +00:00
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
public ISecurityObjectId InheritFrom(ISecurityObjectId objectId)
{
if (objectId is WebItemSecurityObject s)
2019-06-07 08:59:07 +00:00
{
2022-04-15 09:08:06 +00:00
return Create(_webItemManager.GetParentItemID(s.WebItemId).ToString("N"), _webItemManager) is WebItemSecurityObject parent && parent.WebItemId != s.WebItemId && parent.WebItemId != Guid.Empty ? parent : null;
2019-06-07 08:59:07 +00:00
}
2022-03-17 15:13:38 +00:00
return null;
}
2019-06-07 08:59:07 +00:00
2022-03-17 15:13:38 +00:00
public IEnumerable<IRole> GetObjectRoles(ISubject account, ISecurityObjectId objectId, SecurityCallContext callContext)
{
throw new NotImplementedException();
2019-06-07 08:59:07 +00:00
}
}
2022-03-17 15:13:38 +00:00
}