Sponge "Layered" Permissions API Proposal

I was talking a look at some of the most popular of the several dozen Bukkit permissions plugins, and I noticed that in actuality, most of them were doing the exact same thing. They all provided several things:

  1. Object-level permissions(meaning per-user), Bukkit handled only this
  2. Group-level permissions(meaning users are in groups, groups have permissions)
  3. World-level permissions(meaning object- and group-level permissions that override specified ones based on the world)
  4. Permissions config storage. This is very general, meaning SQL storage, YML storage, JSON storage, or other.
  5. Group-level metadata. I’m saying this because it’s pretty important for chat and stuff.
  6. Command-line interface. How the user interacts with the plugin

These plugins share almost the exact same infrastructure. Why not put it in Sponge, with sane defaults?

I think we should stop arguing about whether or not to put in a Permissions API. It’s pretty clear that Bukkit did this to some extent, and it’s going to be done anyway. What we should instead do is logically separate the Sponge API into ‘layers’ as I’ve done above. That way, server owners will be able to get what they want without a billion plugins.

For example, multiple permissions plugins offered SQL storage. What if Sponge offered the infrastructure for permissions and an API for permission storage, and plugins could just implement an interface for permissions storage? That way, there would be a single plugin focused on SQL storage, one focused on MongoDB storage, etc. Sponge would provide a default serialization to HOCON or YML, and the server owner could plug in alternate storage plugins if they wish for alternate storage.

And this should happen for all of permissions, or chat, economy, and other related APIs that aren’t necessarily core Minecraft functions. Sponge should provide a layered system that plugins can exchange and register for. That way we have plugins focusing on a specific layer, not a whole bajillion re-discovering the wheel.

10 Likes

I’m all for this. Permission handling seems like a necessary part of most servers, so it would make a lot of sense to have it implemented in Sponge so we can avoid having to develop using multiple APIs (like Vault on top of Bukkit). Although, I do understand that the API should be kept simple to begin with, the permission handling does seem like a very basic thing to add in.

1 Like

This is excellent. I think that Bukkit got a little confusing for a lot of its newer users with the array of permissions plugins that all were a little bit different. If the API can get one really good system that can be used in 99% of purposes, server administrators would love it. Nice idea OP!

I hope this will be done, that sounds great!

This sounds good, this is probably the one feature that Spigot actually needs within the API, or at least some way for a permissions plugin to easily hook into this. It was way to complicated with:
Bukkit -> Vault -> PEX or PermissionsBukkit

This sounds nice. Its not very vanilla of us though.

I think we should just get a better permission api that allows checking per world / group instead.

We don’t exactly have to implement all the storage stuff.


Also this would have to be OK’ED by the lead devs anyway. But I am sure if enough of the community agrees with it including the dev’s it might be something that can go through!

2 Likes

I love that quote. Though we are basing this whole thing off forge which is basically the opposite of vanilla :stuck_out_tongue:

Indeed. They planned to attempt to keep it as vanilla as possible just like Bukkit. Tell the truth Permissions stuff is something that is really necessary. The storage end of it though might not be. It really depends.

This sounds good in theory…

However I’m not sure it’s the greatest idea ever.

One thing I’m certain wouldn’t work well is out-of-the-box chat formatting options that allow for group metadata like prefixes/titles.

This would mean people have no real options because the only option is what comes ported with sponge which would mean every sponge server would have very similar chat formatting. Sponge shouldn’t touch the chat formatting at all; just keep it completely vanilla. Plugins need to handle chat formatting.

As for permissions, having built-in groups and things doesn’t sound like my cup of tea, either.
Seeing as sponge is the hopeful successor to bukkit I’d like to see it just be something similar to bukkit… A very basic way of defining which permissions non-OP players can use, and which OP-players can use. Nothing more, nothing less… just a basic default setup that permissions plugins can build on top of.

Not to mention permission aliases like bukkit’s permissions.yml file, that could be very useful. (I know it was to me, I can easily define all of my donor perks in one simple and easy permission node that I can just apply to people on the go, instead of adding a whole sub-group to the user.)

I know that a lot of server owners would like to see built-in features to sponge as having things built-in to the server.jar could potentially speed up a lot of processes. However, having things built-in to the server .jar will eventually lead to the server .jar file being bloated, and suddenly the latest version of sponge is over 500 MB in size. That’s not what I want, and I’m sure that’s not what the devs want, either.

One solution I could offer to this would to be to provide some kind of API for inserting your plugins into the server.jar somehow? I don’t really know too much about coding so I’m kind of talking out my ass here, but I think it’d be cool if there were some incentive to allow for plugin developers to insert their code into the server .jar so as to allow for more of these built-in features people keep begging for.

In fact, maybe sponge could have a main directory for downloads, where you can download the ““vanilla”” version of sponge with no extraneous built-in stuff, and then offer other directories in which trusted plugin devs could submit packaged plugins or modified versions of the sponge.jar that make things easier on server admins.

Excuse me for rambling, I just really want to help brainstorm ideas : P

1 Like

That’s because one of the “popular” permissions based plugins was just a refactor of Permissions. A lot of the ones that came after included the same features simply because that is what users were use to and what they had come to expect.

Honestly, I don’t feel that any permission system beyond OP/Non-OP belong in Sponge. Sponge should try to stay as neutral as possible in regards to what the API exposes and provides. Something like a permission system not only isn’t default in Minecraft, it also isn’t needed by a lot of servers and just adds an extra layer of difficulty in setup.

The thing is that essentially every plugin wants some way to know “is the user allowed to perform action X?”, for which “is the user op?” is a reasonable default (and what Bukkit did) for servers with no external permission handling, but without such a somehow-pluggable call in the core API, things are just a huge mess of plugins that are only usable by ops, aren’t compatible with your choice of permission system, conflicting standards, and the like.

2 Likes

I disagree with you @gratimax

Not all servers need the 6 points you listed.
The infrastructure looks similar, but the implementation of the permission plugin is different.
It is good if the user can choice from plugins. If one plugin is perfect then nobody would start a new plugin :wink:
In my opinon the Permission API need three things (similar to @SpaceManiac)

Specification of a Permission API

  1. Has user X permission Y
  2. Give user X permission Y
  3. Remove Permission Y from user X

Optional - Syntax Sugar

  1. List all permissons for each plugin
  2. Give a description for each perm

Not part of the API

  1. List users that have permission X
  2. Groups
3 Likes

Fantastic idea !

My thought is have services that are far more integrated that Bukkit.

Have these services follow a common API, like Vault. This API doesn’t have to cover everything, just enough to satisfy the most common needs of the server and developers. This API is integrated into the server, unlike Vault, making it easy to develop with.

Provide a default implementation, that does what it needs to and not much more. This could just be the user-level permissions, or maybe even groups. Let other plugins override this default, setting themselves as the permission manager for the server. The Permissions API could then be cast to that plugin, to access the individual features that any particular plugin gives. It would give a universal system that’s more robust, but also allow advanced use cases.

Plugins that implement the API could do whatever they want: World permissions, chat formatting, whatever they want. They’d just be required to implement the core features in whatever way they wish, and provide access to the more advanced stuff for those who need it through the casting of this API.

2 Likes

The only useful (again syntax sugar, not needed) from my point of view is,
that “default groups” exists (guest, normal, trusted, mod, admin) and plugins sort their permission nodes
automatically into this groups.

Problems:

  1. What are useful default groups?
  2. Why did we need that in the API, it is server config stuff …

IRC discussion:

09:07] <IDragonfire> btw. what did you thing about that: http://forums.spongepowered.org/t/sponge-layered-permissions-api-proposal/2309?u=idragonfire
[09:07] <jacklin213> i just did @space and smacked tab
[09:07] *** Riking changed nick to Riking|away
[09:08] <jacklin213> tis a bit overkill
[09:09] <IDragonfire> i think the "sponge should have X" and "keep it simple" thread is atm not enough ^^
[09:11] <+zml> sponge is going to start with a simple permissions API that is just interfaces that can be implemented by permissions plugins, though it may be expanded if that is necessary to make stuff work well.
[09:13] *** Cervator quit (Quit: Cervator)
[09:14] <IDragonfire> zml, maybe we need some public specifications ... http://forums.spongepowered.org/t/sponge-layered-permissions-api-proposal/2309/12?u=idragonfire
[09:14] *** jimmikaelkael ([email protected]) joined
[09:15] <jimmikaelkael> hi everyone
[09:15] <jacklin213> hi
[09:15] *** CloakedAlien quit (Remote host closed the connection)
[09:15] <+zml> that line I said is the specification as it exists now :)
[09:16] <+zml> also probably going to have groups and getting all users/groups/whatever with a permission.
[09:17] <+zml> and plugins won't be expected to define permissions -- unless there's a way for default permissions to be specified
[09:18] <+SpaceManiac> not a fan of groups in the API, but a lot of other people seem to be, so ehh
[09:18] <+zml> groups are in the api because lots of people want groups
[09:18] <IDragonfire> why groups should be part of the api?
[09:19] <IDragonfire> lots of people want vault in the api  and X and Y
[09:19] <+zml> I'm at the moment thinking of some sort of abstract permission-subject interface that can be applied to group/player/irc-bot-user/whatever
[09:20] <+zml> IDragonfire: and the API could have something similar to Vault interfaces -- they're super lightweight
[09:20] <+zml> remember that the point of the API is to be useful to plugin developers
[09:20] * waterpicker lands ontop of IDragonfire as a dragon hatchling. He proceeds to rawr.
[09:21] <waterpicker> Hey zml
[09:21] <+zml> hey waterpicker
[09:21] <waterpicker> What you guys talking about?
[09:21] <IDragonfire> http://forums.spongepowered.org/t/sponge-layered-permissions-api-proposal/2309/12?u=idragonfire
[09:21] <+zml> permissions api
[09:22] <+zml> usual arguments pretty much
[09:22] <waterpicker> Ah how is the dicussion going?
[09:22] <IDragonfire> procs and cons, somebody must decide
[09:22] <+zml> I'll write out an initial set of interfaces this weekend in a branch, we can work from there.
[09:23] <IDragonfire> the question is .. if you give user groups ... what will the dev use it for?
[09:23] <Paril> built-in OP group I guess
[09:23] <Paril> a default group for everybody and OP group
[09:23] <+zml> rank ladder type things
[09:24] <Paril> oh, -other- devs? ranks and groups are widely used
[09:24] <Paril> thought he meant within the bounds of Sponge's default implementation
[09:24] <IDragonfire> yes
[09:24] <IDragonfire> that lead to a design problem
[09:24] <+zml> yeah, 2 groups --op and notop
[09:25] <+SpaceManiac> I don't really feel like those are groups wrt how the term is normally used
[09:25] <IDragonfire> if a plugin want a custom "op" group,
[09:25] <IDragonfire> then it should give the user myplugin.groups.myopgroup
[09:25] <+zml> IDragonfire: wait until some code exists then comment
[09:25] <IDragonfire> at runtime the plugin should give the "myopgroup perm" for each user
[09:26] <+zml> nononononono lets not have a ton of plugins storing permissions in 4999999 diferent places
[09:26] <Paril> there's another way that groups could be bypassed entirely, and that's if there could be "pseudo-permission nodes" which essentially act as groups
[09:26] <Paril> and these nodes can add more pseudo-perm nodes, which would effectively recreate inheritence
[09:26] *** Goldman60-Y510P ([email protected]) joined
[09:27] <IDragonfire> Paril, that was the thing i try to descirbe
[09:27] <+zml> yeah, that's a common thing. The issue is that's a bit more difficult to implement rank ladders with
[09:27] <Paril> not entirely, as long as you can give a numerical value to the pseudo-node
[09:27] <+zml> and the perm format for that would be group.<groupname>
[09:27] <+SpaceManiac> "rank ladders" aren't a core concept to permissions
[09:27] <+zml> so options too
[09:27] <Paril> yeah was gonna say
[09:27] <IDragonfire> zml, you try to add feature x to the apu
[09:27] <IDragonfire> *api
[09:27] <+zml> SpaceManiac: they're what people want groups for
[09:27] <Paril> groups having a "rank" isn't something that default would need
[09:27] <Paril> not really
[09:28] <Paril> certain types of servers do but I wouldn't say the majority use ranking
[09:28] <Paril> in a way that requires promote/demote sort of behavior
[09:28] <+SpaceManiac> zml: groups I can kind of concede on, but 0..N orderings of groups to create some linear path is def. not a core concept
[09:28] <IDragonfire> zml, groups must be handled be the creator, otherwise we need "default groups" in sponge
[09:28] <+SpaceManiac> neither are "options" - that's metadata, not permissions
[09:28] <Paril> there could be default groups in Sponge, IDragonfire
[09:28] <+zml> SpaceManiac: options are permissions with a non-boolean value -- they should have similar API
[09:28] <Paril> non-op and op are concepts that exist in Minecraft that can be faked through permissions
[09:29] <+SpaceManiac> somehow that argument has never convinced me
[09:29] *** Goldman60 quit (Ping timeout: 206 seconds)
[09:29] <Paril> I've always thought of permissions as being a yes or no situation
[09:29] <IDragonfire> from my view a normal plugin check against a permission x for function y ... the only "cool thing" is that a plugin can automatcilly sort the permissions into groups like normal, mod, op ...
[09:29] <+SpaceManiac> guess I'll wait and see, I'm out for the night
[09:30] <+zml> think of something like prefix -- it has inheritance, can be specified in a specific context, just like a permissions node except it has a string value
[09:30] <Paril> this is true, but like SpaceManiac said that's metadata, not a permission
[09:30] <Paril> unless you look at it as "I give this group permission to have a prefix of x"
[09:30] <Paril> but that just sounds weird
[09:30] <IDragonfire> keep it simple: http://forums.spongepowered.org/t/keep-it-simple-spongeapi-application-interface-utils/2307
[09:31] <+zml> think of permissions as a specialization of metadata and it's less weird rather than the other way around
[09:31] <Paril> permissions should be yes or no, that seems like it can be optimized a bit better
[09:31] <Paril> exactly how metadata like prefix would be applied to groups i dunno
[09:31] <Paril> guess it depends how it would be structured
[09:31] <+zml> like it works with something like PEX
[09:32] <Paril> in PEX it's separate to the "permissions" array
[09:32] <Paril> it's metadata, not a permission on its own
[09:32] <+zml> it's implemented the same... (saying this as the dev of PEX)
[09:33] <Paril> implementation isn't what I'm talking about, moreso the structure
[09:33] <+zml> api is also basically the same. nobody cares about file formats at this point
[09:33] <Paril> I don't remember using hasPermission for prefix
[09:34] <Paril> was there not a specific getPrefix function?
[09:34] <+zml> ...
[09:34] <+zml> there was, but that's been replaced in favor of getOption("prefix")
[09:34] <Paril> okay, so it's under options and not permission
[09:34] <Paril> so they are two separate concepts there
[09:35] <+zml> this is going in circles
[09:35] <Paril> I don't get what your argument is, you want metadata to be a permission but also like PEX where it is an option
[09:35] <+zml> you refuse to see how the two highest-level API methods are basically the same at lower levels.
[09:35] <+zml> metadata is options
[09:35] <Paril> right
[09:36] <Paril> and no, I don't see how they are the same at the lowest levels; of course it depends how it's implemented, that's a given, but if permissions array is kept strictly boolean it should be easier to optimize per user/group
[09:36] <Paril> I think they should be separate at both levels, but that's just me
[09:36] <Paril> I don't know. Interested to see what the core devs have in mind for it, if they have thought about it
[09:37] <+zml> how about no more permissions discussions until code exists? :)
[09:37] <IDragonfire> zml, only because the implementation can be the same (or perm can use the metasystem) the api must not be the same  !
[09:37] <+zml> how about no more permissions discussions until code exists? :)
[09:38] *** Sleaker quit (Ping timeout: 201 seconds)
[09:38] <IDragonfire> implementation code or interfaces?
[09:38] <+zml> interface
[09:38] <Paril> I guess my main point is that just because it may make sense to merge them because booleans can indeed be lumped into an object that they shouldn't be, because the array of allowed permissions can be optimized differently than a simple key/value pair can be
[09:38] <+zml> implementation is probably going to be a permissions plugin.
[09:38] <IDragonfire> post it in the forum ;)
[09:39] <+zml> uh fuck no, this is going into a branch on github

or:
no groups into api … instead it exists a external site (+plugin, e.g. groupperm) where plugin authors can add/upload their plugins … the side check the code for the permission nodes and the author can specify default groups … the groupperm plugin fetch the data from the site …


Statement from @sk89q:

[10:10] <sk89q> for perms
[10:11] <sk89q> we can have very basic calls (hasPermission() ...)
[10:11] <sk89q> more advanced stuff can be service stuff
[10:11] <sk89q> once again, not top level api
[10:11] <sk89q> just crap we haev around for utility
[10:11] <sk89q> in some of other stuff I write, everything is a service lel
[10:11] <sk89q> even config
[10:11] <+zml> well the basic calls would go to the service eventually, since that can already handle plugins providing an implementation
[10:11] <luacs1998> "IMPLEMENTATION DETAILS" - lex
[10:11] <sk89q> no that's not implementation details
[10:11] <sk89q> that's api details
[10:12] <sk89q> yeah we can do service for perms too
[10:12] <sk89q> however
[10:12] <sk89q> the question is if we want hasPerm() on players, etc.
[10:12] <luacs1998> well
[10:12] <sk89q> on another note
[10:12] <+zml> I think it would be useful to have + make things simpler
[10:12] <sk89q> the nominal way in Java
[10:12] <sk89q> is not the way we are doing it
[10:12] <sk89q> with JAAS you
[10:12] <sk89q> get a Subject from a LoginModule
[10:12] <sk89q> and you check perm on Subject
[10:13] <sk89q> here we basically compile login + check into one call
[10:13] <sk89q> with the Subject you do have the advantage is that you decouple context from the point of permission check
[10:13] <sk89q> otherwise
[10:13] <sk89q> hasPerm(perm, context)
[10:13] <sk89q> though arguably you could pass around a context, but contexts won't be as rich as a custom Subject
[10:14] <sk89q> I used that https://github.com/sk89q/Eduardo/blob/master/src/main/java/com/sk89q/eduardo/auth/AuthService.java
[10:14] <sk89q> the plus is later
[10:14] <sk89q> I can maybe
[10:15] <sk89q> Subject login(totally something different)

Instead of trying to shove everything into the API just have “official” plugins that the main devs develop, they should be open source.

If other developers want to improve the functionality, then they can fork it or extend it like an API.

It would at least reduce this issue: http://xkcd.com/927/

2 Likes

“List all permissons for each plugin”

This should be a MUST HAVE for any permission plugin/api/whatnot.

My opinion is that Sponge infrastructure should not permit an end-run around permissions. How that is accomplished I am not sure.

I though somebody would asks it earlier …

  1. There is no “Permission”-Node register system, plugin ask for permission at runtime
  2. The permission Plugin has a list of all “Permission”-Nodes where one users has the node
  3. Why a plugin want a list of all permissions?

The only thing that was always missing are offline user permissions. And there is some stuff that should be optional (but specified by the API, so that there is a standard plugin makers can implement).

Must-have: Permission Check

The essential method of a permission API is

permPlugin.hasPermission(UUID playerId, String permission)

I think it should work for online and offline players!

Must-have: permissions.yml##

And also important, groups can be handled with custom parent permissions (like the permissions.yml in Bukkit). I think many admins didn’t know how it worked.
That’s a must-have for sponge!

"permissions": {
    "myperms.basic": {
        "chatplugin.usecolors": true,
        "protectionplugin.build": true
    },
    "mygroups.user": {
        "myperms.basic": true,
        #give users User tag
        "chatplugin.tag.User": true
    },
    "mygroups.admin": {
        "myperms.basic": true,
        #give admins Boss tag
        "chatplugin.tag.Boss": true
        "worldedit.*": true,
        "mailplugin.sendtoall": true,
        "adminplugin.ban": true,
        "adminplugin.kick": true
    },
}

So when you give a player mygroups.admin, he gets all permissions listed under myperms.basic (just like users) and the additional ones…

Optional: Permission Management##

There could be an optional interface for permission management:

permPlugin.setPermission(UUID playerId, String permission, boolean value, PermissionContext ... context)
...

Context could be a WorldContext object to restrict the permission to one world, or TimeContext to limit it to a certain in-game time, or a custom context object (plots, regions, whatever).

And a getter with context support

permPlugin.hasPermissionByContext(UUID playerId, String permission, PermissionContext ... context)
...

Optional: Permission/Player Lists##

There could also be an optional interface for player listing:

//gets all online and offline players who have or have not the permission in the context they are in right now
List playerList = permPlugin.getPlayersByPermission(String permission, boolean value)
...
//gets all online and offline players who have or have not the permission in the specified context
List playerList = permPlugin.getPlayersByPermissionAndContext(String permission, boolean value, PermissionContext ... context)
...

That means to get a list of online and offline players who can build in a world, you can just specify a WorldContext.
And permission lists:

//gets all online and offline players who have or have not the permission in the specified context
List permissionList = permPlugin.getPermissionsByContext(UUID playerId, PermissionContext ... context)
...

The permission plugin##

The plugin decides how it handles (or ignores) the context, how it saves permission andcontext data (extra table in database etc.) and anything else.
The only thing the server does is find all parent permissions (specified by plugins, or in the permissions.yml) that include the permission that is asked for:

plugin checks if player.hasPermission("protectionplugin.build")
>
server finds all parent perms that include it:
- protectionplugin.build
- myperms.basic
- mygroups.user
- mygroups.admin
>
server asks permPlugin if player has any of these
permPlugin.hasPermission(player.getUniqueId(), "protectionplugin.build") --> false
permPlugin.hasPermission(player.getUniqueId(), "myperms.basic") --> false
permPlugin.hasPermission(player.getUniqueId(), "mygroups.user") --> true
>
Yay, found one! return true;
1 Like