151 lines
3.7 KiB
C#
151 lines
3.7 KiB
C#
using NATS.Server.Subscriptions;
|
|
|
|
namespace NATS.Server.Auth;
|
|
|
|
public sealed class ClientPermissions : IDisposable
|
|
{
|
|
private readonly PermissionSet? _publish;
|
|
private readonly PermissionSet? _subscribe;
|
|
private readonly PermissionLruCache _pubCache = new(128);
|
|
|
|
private ClientPermissions(PermissionSet? publish, PermissionSet? subscribe)
|
|
{
|
|
_publish = publish;
|
|
_subscribe = subscribe;
|
|
}
|
|
|
|
public static ClientPermissions? Build(Permissions? permissions)
|
|
{
|
|
if (permissions == null)
|
|
return null;
|
|
|
|
var pub = PermissionSet.Build(permissions.Publish);
|
|
var sub = PermissionSet.Build(permissions.Subscribe);
|
|
|
|
if (pub == null && sub == null)
|
|
return null;
|
|
|
|
return new ClientPermissions(pub, sub);
|
|
}
|
|
|
|
public bool IsPublishAllowed(string subject)
|
|
{
|
|
if (_publish == null)
|
|
return true;
|
|
|
|
if (_pubCache.TryGet(subject, out var cached))
|
|
return cached;
|
|
|
|
var allowed = _publish.IsAllowed(subject);
|
|
_pubCache.Set(subject, allowed);
|
|
return allowed;
|
|
}
|
|
|
|
public bool IsSubscribeAllowed(string subject, string? queue = null)
|
|
{
|
|
if (_subscribe == null)
|
|
return true;
|
|
if (!_subscribe.IsAllowed(subject))
|
|
return false;
|
|
if (queue != null && _subscribe.IsDenied(queue))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
public bool IsDeliveryAllowed(string subject)
|
|
{
|
|
if (_subscribe == null)
|
|
return true;
|
|
return _subscribe.IsDeliveryAllowed(subject);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_publish?.Dispose();
|
|
_subscribe?.Dispose();
|
|
}
|
|
}
|
|
|
|
public sealed class PermissionSet : IDisposable
|
|
{
|
|
private readonly SubList? _allow;
|
|
private readonly SubList? _deny;
|
|
|
|
private PermissionSet(SubList? allow, SubList? deny)
|
|
{
|
|
_allow = allow;
|
|
_deny = deny;
|
|
}
|
|
|
|
public static PermissionSet? Build(SubjectPermission? permission)
|
|
{
|
|
if (permission == null)
|
|
return null;
|
|
|
|
bool hasAllow = permission.Allow is { Count: > 0 };
|
|
bool hasDeny = permission.Deny is { Count: > 0 };
|
|
|
|
if (!hasAllow && !hasDeny)
|
|
return null;
|
|
|
|
SubList? allow = null;
|
|
SubList? deny = null;
|
|
|
|
if (hasAllow)
|
|
{
|
|
allow = new SubList();
|
|
foreach (var subject in permission.Allow!)
|
|
allow.Insert(new Subscription { Subject = subject, Sid = "_perm_" });
|
|
}
|
|
|
|
if (hasDeny)
|
|
{
|
|
deny = new SubList();
|
|
foreach (var subject in permission.Deny!)
|
|
deny.Insert(new Subscription { Subject = subject, Sid = "_perm_" });
|
|
}
|
|
|
|
return new PermissionSet(allow, deny);
|
|
}
|
|
|
|
public bool IsAllowed(string subject)
|
|
{
|
|
bool allowed = true;
|
|
|
|
if (_allow != null)
|
|
{
|
|
var result = _allow.Match(subject);
|
|
allowed = result.PlainSubs.Length > 0 || result.QueueSubs.Length > 0;
|
|
}
|
|
|
|
if (allowed && _deny != null)
|
|
{
|
|
var result = _deny.Match(subject);
|
|
allowed = result.PlainSubs.Length == 0 && result.QueueSubs.Length == 0;
|
|
}
|
|
|
|
return allowed;
|
|
}
|
|
|
|
public bool IsDenied(string subject)
|
|
{
|
|
if (_deny == null) return false;
|
|
var result = _deny.Match(subject);
|
|
return result.PlainSubs.Length > 0 || result.QueueSubs.Length > 0;
|
|
}
|
|
|
|
public bool IsDeliveryAllowed(string subject)
|
|
{
|
|
if (_deny == null)
|
|
return true;
|
|
var result = _deny.Match(subject);
|
|
return result.PlainSubs.Length == 0 && result.QueueSubs.Length == 0;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_allow?.Dispose();
|
|
_deny?.Dispose();
|
|
}
|
|
}
|