Skip to content
Nill edited this page Jul 8, 2026 · 6 revisions

Access Lists and Entries

An access list is a list of access entries tied to a given secured object. Access lists are stored and managed by the security provider which is scoped to the security consumer, such as a Bot or Client.

That was a lot of words, so let's try using an example:

You want to disallow Bob from executing the "/weather" command because he's been abusing it. What you want to do is create a deny entry on the "/weather" secured object that matches Bob's user id.

var ace = bot.Security[WeatherCommand].AccessList.AddUser(bobs_id, Permission.Use, AccessType.Deny);
ace.Comment = "Abuse";
ace.Expires = DateTime.UtcNow.AddDays(1);

Looks pretty simple, right? What's happening here is that bot.Security[WeatherCommand] is firstly resolving the security provider for bot and then using it to get an object called the security accessor (ISecurityAccessor) for the WeatherCommand object; the security accessor is used to provide convenient access to security operations such as updating the object's access list.

The AddUser() method created an AccessEntry for bobs_id (which was later returned as local variable ace) prior to adding it to AccessList, which is the access list for the WeatherCommand object within the scope of bot.

When Bob goes to use the /weather command, the Toolkit's Command object will call Context.AssertSecurity(command, Permission.Use) which will either do nothing (most users) or throw an UnauthorizedAccessException (in the case of Bob).

What is happening is that the SecurityExtensions.AssertSecurity(this Context) extension method is resolving the security provider for Context.Sender (e.g. the Bot) and invoking its AssertSecurity(item, permission, type) method, which in turn looks up the access list for item (the command object) and calls its AssertSecurity method, which walks the access control list, evaluating each entry.

If an UnauthorizedAccessException is thrown, this will not break your bot or make your webhook unhealthy because this exception (and many others) are caught by Telefrag and returned to the user as a failure message. You can configure this in Toolkit.Settings.UserAccessDeniedHandling for access denied errors (and UserErrorHandling for all other errors).

Permissions

Permission is an enum that contains well-known values used to make access decisions.

Value Name Description
0x1 Use Use, invoke, execute the object
0x2 Read Arbitrarily read any readable properties from the object
0x4 Modify Arbitrarily write any public writable properties to the object
0x80 ChangeAccess Ability to modify the object's access list or other security parameters
0xFF FullControl All permissions

Granting a user access to an object does not necessarily provide any mechanism with which to enact changes or query the object unless you are running the UtilityBot which provides access to authorized users via Telegram to read, modify, and execute objects, privileges withstanding.

Extending Telefrag's Security

Telefrag's core works only with interfaces that describe as little as possible leaving as much room for extensibility as possible. Start out by implementing ISecurityProvider and the rest should follow by way of dependency requirements;

  • ISecurityProvider is the root of security customization, the implementation is used to provide Telefrag with your access lists and authorization evaluation functions. Each sender (e.g. Bot) can only have one security provider, but you can write one which easily encapsulates the default implementation. A Bot's security provider is configured in its BotPrecursor structure or during instantiation.
  • IAccessList just needs to be an IEnumerable<IAccessEntry> and an IList<AccessEntry> with one method:
    • Clean() - Called by the security provider when the list should purge expired or invalid entries.
  • IAccessEntry ties a Permission and ISecurityPrincipal together, but it doesn't prescribe how. It only needs to implement some feeler methods:
    • IsExpired - Is the entry expired (and thus no longer evaluated against)?
    • IsDeny - Does the entry deny access?
    • IsAllow - Does the entry allow access?
    • IsAudit - Should Telefrag audit (log) each match of this entry?
    • Matches(user) and Matches(context) - Allows the entry to determine if it matches a given user object or Context.
    • Validate() - Asks the entry to check if it's valid and throw an exception if it's not

This interface design allows for future access entries that can match using arbitrary business logic. In our implementation, AccessList and AccessEntry implement these interfaces respectively.

AccessList has a property SecurityMode which allows you to set whether evaluation defaults to allow or deny when there are no matching entries. Default is deny (as in Windows and most other security environments).

Clone this wiki locally