Basics: Aces & Principals
Aces and principals are the default “permissions” system built into fxserver. It’s very easy to use, as long as you know the basics and you just start trying out some stuff.
It’s also very easy to use this from within resources. Just use ExecuteCommand()
to add/remove aces or principals, and use IsPlayerAceAllowed()
to check if a player is allowed access to an ace (either directly or via inherited permissions).
Principals
Let’s start by taking a look at what a Principal is, and how you can use it in the most simplistic way.
Principals are identifiers that hold permissions (aces). Those identifiers can either be player identifiers (ip, steam or license), or they can be made up identifiers (like: group.admin
, group.moderator
, vip
or snail
).
Command syntax
The command used to add identifiers has the following syntax:
# Adds the child principal to the parent principal.
add_principal <child_identifier> <parent_identifier>
# Removes the child principal from the parent principal.
remove_principal <child_identifier> <parent_identifier>
Example
Let’s say we have 2 players. “Player A” and “Player B”. We’ll assume that their (fake) identifiers are:
player:a
andplayer:b
. We also have 2 groups, which are identified by:snail
andgroup.admin
.
To add “Player A” to the “snail” group, you can use the following command in the server console:
add_principal identifier.player:a snail
Now, all aces that get added to the “snail” group, will automatically be set for identifier.player:a
(so “Player A”).
Inheritance
Principals can also inherit from other principals. For example, if we want the “group.admin” group to also get all permissions from the “snail” group, you’d do this:
add_principal group.admin snail
NOTE There is an important catch with using inheritance, which will be explained in the Aces section.
builtin.everyone
The builtin.everyone
principal is a “group” that every single player is in. This means, if you allow builtin.everyone a specific ace, everyone will have that ace as allowed.
Even if you add someone to a specific group/principal, they will still always inherit all permissions from builtin.everyone
.
At this point, the inheritance tree should look something like this:
builtin.everyone # (global parent of everything)
|
| .... snail # (parent & child)
| |
| .... +---- group.admin # (child, has all "snail" permissions)
| |
| .... +--- identifier.player:a # (child, has all "snail" permissions)
Aces
Aces can be seen as a “permission node”, which can either be allowed or denied.
By default, all aces are set to unset
aka deny
. Which means, that if you were to check for an ace that was not setup, it will return false
(deny).
The default unset
value can be overwritten by (manually) setting it to either deny
or allow
. Setting something to deny
will actually set it to DENY-ALWAYS
. Which means, it can NOT be overwritten by something like parent principals. Setting it to allow
will grant the ace and is also NOT able to be overwritten by parent principals. Basically it’s just a fist come first serve principle, the first permission to be set, cannot be overwritten by setting it to the opposite state after setting the first state.
Ace-command syntax
# Adds the ace to the principal, and either "allows" or "denies" it.
add_ace <principal_identifier> <ace_string> <allow|deny>
# Removes the ace from the principal, note it only removes the "allow" or "deny" ace, depending on whichever one you select.
remove_ace <principal_identifier> <ace_string> <allow|deny>
To illustrate this, take a look at the following example:
Example
Let’s take Player A and Player B, snail and group.admin principals from the previous example.
In the previous example, we added PLayer A to the snail group, and we also set the group.admin group to inherit everything from the snail principal (group)
Let’s say that Player B has been added to the group.admin principal. (add_principal identifier.player:b group.admin
)
At this point, the inheritance tree looks like this:
builtin.everyone # (global parent of everything)
|
| .... snail # (parent & child)
| |
| .... +---- group.admin # (parent & child, has all "snail" permissions)
| | |
| .... | ... +--- identifier.player:b # (child, has all "group.admin" AND all "snail" permissions)
| |
| .... +--- identifier.player:a # (child, has all "snail" permissions)
If we want to give Player B the i.am.cool
ace, we 4 options to do so in this current setup.
- Add the ace to
builtin.everyone
- Add the ace to
snail
- Add the ace to
group.admin
- Add the ace directly to
identifier.player:b
However, we probably only want to add it to the 3rd or 4th option. Because adding it to 1 will grant it to everyone, and we don’t want that, and adding it to option 2 will allow everyone in the snail group to use it, which is also not what we want in this case.
So to add the i.am.cool
ace to the group.admin
principal, we’d do something like this:
add_ace group.admin "i.am.cool" allow
The group.admin
principal, and all of it’s child principals (in this case, identifier.player:b
), now have access to the i.am.cool
ace.
Wildcards
Of course, aces have wildcards!
So, let’s say we want to give Player A permission to every i.am.***
ace, because Player A is .cool
, .awesome
and .snailsome
as well. Then we can simply add the i.am
ace to identifier.player:a
, now player a has every i.am.***
ace.
add_ace identifier.player:a "i.am" allow
# Player a is now: cool, awesome and snailsome!
Player B however, is still only cool
. Let’s make Player B snailsome
as well, because they’re part of the snail
group after all. But we DON’T want to give them the i.am.awesome
ace. In this case, we could simply add the i.am.snailsome
ace to either the group.admin
or identifier.player:b
principals, but we’re going to do it slightly different, just because WE CAN. So how are we going to do it you may ask? Well just like this:
add_ace group.admin "i.am.awesome" deny
add_ace group.admin "i.am" allow
# Player b is now: cool & snailsome but NOT awesome!
Notice how we set the deny
for the i.am.awesome
first, and then we set the i.am
wildcard to allow. Remember what we said about the first come first serve principle?
Now, group.admin (and thus Player B) has access to all states i.am.cool
and i.am.snailsome
EXCEPT for one, which is the i.am.awesome
ace, because we set that to deny FIRST.
Commands overview
To summarize everything above, here’s a quick overview of all commands + 2 commands that aren’t listed above.
Command Syntax | Description |
---|---|
add_ace <principal_identifier> <ace_name> <allow/deny> |
Sets the ace for the specified principal identifier to either allow or deny. |
removes_ace <principal_identifier> <ace_name> <allow/deny> |
Removes either the allow or deny ace for that principal. |
add_principal <child_principal> <parent_principal> |
Adds the child principal to the parent principal, giving the child all aces of the parent principal. |
remove_principal <child_principal> <parent_principal> |
Removes the child principal from the specified parent principal (revoking all previously inherited permissions). |
Bonus commands | |
list_aces |
Will show a list of all aces, for each principal identifier and show’s the granted status (allow, deny(/unset) or deny-always) |
list_principals |
Will show a list of all principals (child > parent) |