Major release today, entirely focused on one subject: Querki's security system has gotten a major rewrite.tl;dr:
There is now a "Security for" item in the Actions menu, which provides a halfway-decent UI for managing the Security for this Space, Model or Thing. And the notion of security "inheritance" has been massively rewritten, to make more sense.
On to the gory details...
First, a reminder of how security works in Querki. There are actually two security models, which are closely related but intended for different situations. The "coarse-grained" system is intended for most use cases, and is built around the notion of "Roles". The system has several pre-canned Roles, which carry particular permissions across the Space. Each one has all the permissions of the ones before it, and adds a bit:
- Basic Member: can read stuff in this Space, and that's about it.
- Commentator: can comment on Things.
- Contributor: can create and edit Instances.
- Editor: can design Models, and (once the notion of Moderation is in place) will be able to moderate Conversations and approve outside contributions.
- Manager: not yet implemented, but will be able to do *nearly* everything the Owner of the Space can do.
And while it's not listed officially, the Owner of the Space can do anything to it -- it's not possible to lock out the Owner. (There is also a nascent concept of Custom Roles, but we're barely started on that.)
This coarse-grained approach is by far the easier way to go, and hasn't changed in this revamp. It's controlled from the Sharing page for the Space, which lets you say what Role to give someone when you are inviting them, and to change their Role later. I recommend that most people, most of the time, just use this Role-based system: it's easy to understand and suffices most of the time.
Today's changes concern the lower-level and older "fine-grained" system. This is actually a richer security model than most application frameworks provide out of the box: you can control exactly who has which permissions across the Space, for a particular Model, or for individual Things. This lets power users tweak and tune the edge cases to their liking: making *this* page Public in an otherwise Private Space, or locking down a few Things to only be accessible to the Editors. (Note that you can consider it an "add-on" to the Role-based approach -- even when doing fine-grained work, I recommend viewing that as tweaks to the Roles.)
The fine-grained system is very powerful, but it's also traditionally *very* hard to use -- you needed to add particular Advanced Properties by hand in the Advanced Editor, and fill them in with the correct values. Even I found it to be a pain in the tuchus.
Worse, I made some design mistakes early on in how "inheritance" worked in this system. Specifically, I was wrestling with the problem that you needed to be able to restrict who could design a given Model, while allowing more people to create and edit its Instances. Similarly, I needed a way to declare Space-wide who could by default edit the Instances of this Space, separately from being able to edit the Space itself. So I added what proved in retrospect to be a horrible hack: the Who Can Edit Children Permission. That almost made sense, until I began to realize that all the same issues pertained to all the other permissions as well.
So I've thrown out Who Can Edit Children entirely -- it's now deprecated, and likely to be deleted once all Spaces have evolved to the new approach. We now have a concept of the "Instance Permissions object" on each Space and Model. The one on the Space contains the Permissions that are, by default, applied to all Things in the Space; the one on a Model contains the default Permissions for that Model's Instances.
Just as importantly, though, that detail is now hidden from you, replaced by a specialized Security Page, which you can get to from the Actions menu. This lists the Permissions that are relevant to the Thing you're looking at, with straightforward radio buttons to let you choose what you want. If you're looking at the Space, it has a secondary tab marked Instances, which lets you set the default Space-wide Permissions for all Things. If you're looking at a Model, it also has an Instances tab, which lets you set the default Permissions for all Instances of this Model.
There are five options that may be available for any given Permission:
- Public: if checked, everyone (even Anonymous viewers from the Web) can do this. Public is only available for "read-like" Permissions for the time being.
- Members: if checked, all Members of the Space can do this.
- Owner: if checked, then only the Owner can do this.
- Custom: if checked, this shows a Tag Set input box, that lets you specify exactly the Persons and Roles that can do this. This is *really* getting down into the weeds, but is how you get access to the full power of the system when you need it.
- Inherit: when looking at a Model's or Instance's Security page, this is the default, and simply means that it should inherit the value from "above" -- the Model inherits from the Space's Instances tab, and the Instance inherits from the Model, or if that's marked Inherit as well, it picks it up from the Space's Instances tab.
I'm not going to claim that this approach is perfect: there's still a lot going on here. But I believe it's an enormous improvement: it gives you quick and easy access to exactly the options that are legal for the Thing you're looking at, and the common options are simply a click. And the change to the actual security model means that Spaces and Models now have their own Permissions, entirely separate from those of the Instances that inherit from them.
Existing Spaces should be automatically "evolved" to use this approach when you next load them: the Instance Permissions objects will be automatically created, and the Permissions currently on the Spaces and Models will be copied as appropriate. (Note that existing Who Can Edit Children values will become Who Can Edit on the new Instance Permissions object.) I've tested this pretty heavily, but *please* check it out and tell me ASAP if you find problems. This is a big enough rewrite that bugs wouldn't be surprising, and security is one of the areas where bugs are generally not tolerated.
One significant change, although I don't believe it affects anyone but me yet: previously, if you marked the Space as not publicly readable, that meant that it was *hidden* from non-Members -- if a non-Member tried to access that Space at all, the system would deny that it even existed. I've decided that that's a poor way to implement Hidden, especially because it prevented you from opening just one or two pages in a Space where the root wasn't Publicly readable. So that's been removed; we'll eventually add a first-class "Hidden" flag for this purpose.
Related to that: the Who Can Read Permission is a bit "soft" when it comes to the Space itself. For Models and Instances, Who Can Read is quite absolute: if you don't have Who Can Read on a Thing, it doesn't exist
in your view of the world. Literally -- it gets snipped out of your view of the Space, which means that we're pretty confident about that. We can't do that for the Space, though -- it would be hugely destabilizing -- so instead it currently just hides the Default View with an error message. This undoubtedly has edge cases that need fixing, and in general this will need improvement.
And related to that
: the Security UI currently allows you to mark a Model as non-Readable, while its Instances are Readable. Don't do that. Like I said, if something's non-Readable, it doesn't exist at all -- so if you hide the Model, odds are good that you're going to get unexpected behavior. Again, this is an edge case that probably needs more thought and improvement.
The sharp-eyed may notice that there is a new Who Can Design Permission, separate from Who Can Edit. This was driven by the realization that designing Models is fundamentally different from Creating and Editing Instances, and will often have different permissions. Think of Who Can Design as being the combination of Create and Edit, specifically for Models.
Also, note that the Sharing Page has been broken into several tabs -- that page was getting pretty long anyway, and I needed to learn how to use Bootstrap Tabs.
Finally, here's the Rosetta Stone to understanding permissions, if you really want to grok the system exactly. When we are looking up whether you are allowed to do perform an action on a Thing, we ask, in order:
- Does this Thing explicitly set this permission? If so, follow what that says. If it says "Inherit"...
- Does its Model's Instance Permissions have it set? If so, do that. If that says "Inherit"...
- Do you have a Role that gives you this Permission? Is so, allow it. Otherwise...
- Do what the Space's Instance Permissions say.
It's not a trivial system, but I believe it fits the Querki approach to the world well, and now that the new UI is in place, it should be at least adequately usable...