Over-engineering a permissions system
March 14, 2009 – 8:58 pmAs before, I’m still working on a WebManager library / framework / toolbox, and a next step in that is to improve the system’s authorization system. From my understanding, this works roughly as follows:
In WebManager, as described in my previous post, a WCB is made out of several Components, such as a form, an element, etcetera. Each component (although ‘each’ isn’t a fact, fyi) has, next to a basic set of settings, also an optional setting for permissions. With permissions, I refer to access control lists (of sorts) for the five (or so) basic usergroups that exist in WebManager, usergroups such as authors, users, developers, etcetera. Each usergroup can have a set of permssions assigned to them, which indicate what that user can do. These permissions can then, in the controller or in a .JSP file, be checked again using WebManager’s AuthorizationService, a service object with some permission checking methods.
A permission is defined as follows. First, you create a Category, basically a parent for each permission. The Category is defined as a Category instance, which gets passed a ‘category’ string, an unique identifier for that category. Usually, at least in the default archetypes, this identifier is equal to the component’s bundle ID, which in turn is a combination of the WCB’s ID and an appendage (such as ‘element’ or whatnot). This results in a category string similar to, for example, “info.greatjustice.wcb.somewcb.element”.
Next, one creates a set of Permission objects, which are objects created according to a permission string (a should-be unique string) and the category defined before. The permission string is usually the category string, with the permission itself appended to it (such as ‘.update’, ‘.delete’, etc). This leads to a permission string of ‘info.greatjustice.wcb.somewcb.element.update’, for example.
Now that there’s a set of permissions (we’ll use the base set of CRUD permissions as an example here - create, read, update, delete), we can assign them to the usergroups that have these permissions. When no permissions are defined, all users have full access to the WCB component. When just one permission is set in one usergroup, that usergroup can only perform that action, nothing else. Anyways, to assign a permission to a permission group, the ComponentDefinition object, which is used to configure and (by WebManager itself) initialize a WCB’s component, has a method, setPermissionsForPermissionGroup(), that allows the setting of a permission. The method takes two arguments, the usergroup (which is a constant string defined in WebManager’s WCBConstants class) and an array of Permission objects to assign to that usergroup.
Next to that, the Element component type has a few extra methods (setCreatePermission and setDeletePermission) that, I assume, sets a global permission that indicates that component can be created and deleted, or in this case, can be inserted or removed from a page - regardless of user rank, i.e. ‘global’.
Now, back to the topic at hand and my own work on this, I figured that this system wasn’t ideal, for a number of reasons.
First, there’s an enormous amount of freedom associated with setting a permission. Because you can pass strings, there’s no way of knowing whether it’ll ‘work’ until you try it out. There’s no set specification about what input is allowed, and nor is there any checking for proper values. This leads me to believe that the whole permission system in WebManager is little more than a string comparison system (as in, if the usergroup identified by this string has the permission defined by that string, return true, else return false), which is fine in itself, but then, why’s there the complexity in the assigning of the permissions? Why bother creating a long permission string when you could just fill in “Slartibartfast” as a permission, and check if a user has the “Slartibartfast” permission all the time?
I can understand that, of course, since I’m sure the system would allow checking for a permission set in component A in component B, with this relatively low-level approach. Still though, I believed that this system could be improved. The lowest step, the assigning of the permission category is pretty much the starting point. I don’t believe that that could be abstracted any more, at least not without completely automating the system of assigning permissions, so that’ll largely stay the same.
The permissions themselves though could be largely automated. There’s a few facts we know about the permissions:
- The permission string is always (or, 99.9% of the time) based on the category’s string.
- The permission is in most cases one of Create, Read, Update, or Delete, and in exceptional cases it’s a similar system with other permissions such as ‘UpdateSomePart’.
- The permission is never used in a dynamic sense - once a permission has been created, it doesn’t turn into something else.
- The usergroups are a pre-defined set of 5 groups, currently defined as plain strings.
Now, with these above facts in mind, there’s a number of things we could do to improve on the permission system.
- Add typesafe constraints to the permissions and usergroups
- Auto-generate permissions based on sensible defaults
- Auto-generate permissions based on what a user wants
Note that there’s one or two additional points to the above list, but they apply to the entire library in a wider sense of the word - i.e. an alternative / easier method of creating ComponentPermissions. I’ll do a full article on that once it’s finished.
We’ll want to improve on the permission system for a number of reasons. First, we’ll want to make it more typesafe - if you know there’s a limited set of usergroups (5, in this case), why would you want to have the users set it as a string? If you know a permission is always a fixed value, why set it as a string value that allows everyone to freely fill things in?
Second, we’ll want to automate - in several layers of meaning - the process of creating and assigning permissions. If you know the category and know the set of permission types, it’s easy to auto-generate the Permission objects and assign them to the ComponentDefinition automatically. Automating in ’several layers’ mean, in this case, that there’s the possiblity to have all permissions auto-generate (the base CRUD permissions, for example), but at the same time not restrict the users in defining their permissions.
After a few days of development (or something, I don’t really keep track of time - I don’t seem to have any deadline or other important tasks where I work), The end-product consisted of a set of components that allow for easy and typesafe definition of permissions, with several layers of automation and customization.
One of the first things I did was to put the permission groups into an enum, a language feature I’ve never used until about 9 months ago, but which I already love. Using an enum instead of the constant string values defined in WebManager’s WCBConsts has the main advantage of being typesafe - when you have a method that expects a usergroup, you can only accept usergroups, instead of having to do a manual check to examine the string value passed to it. The setPermissionsForPermissionGroup could, if WebManager used the enum approach, accept a permission group and an array of Permission objects instead of ’some’ string and an array. This guarantees that there is no way that a user could ever enter the wrong value, simply because the software wouldn’t compile if there’s an incorrect value set there.
The second thing I did was to make my own subclass of the PermissionCategory object, which, at first, just defined a constructor that forced each mandatory value to be set at object create-time - a PermissionCategory requires two or three values in order to function properly, but those values could only be set using setter methods. The custom permsision category defined a single constructor that forces the user to define all two or three values in one go, so it becomes impossible to ‘forget’ a value. This approach is also used in the ComponentDefinition replacement code in the same library, but as said, more on that in a later article.
Later, the custom PermissionCategory got a few additional methods that created Permission objects. A Permission always has a Category as its parent, so why not invert it and have a Category spawn its Permissions?
As said earlier, a Permission’s permission string is usually the same as the Category’s permission string, so why not base a Permission’s string on the Category’s string with just a small appendage (’.create’, for example)?
In this approach, I once again returned to the enum. Defined a Permissions enum that defined four permissions: Create, Update, Read, and Delete. Each had a string representation as well defined inside the enum, string representations in the form of ’.create’, ‘.update’, ‘.read’, etcetera.
The permissions enum, in combination with the custom PermissionCategory, resulted in a ‘createPermission’ method in the PermissionCategory that took just one parameter, an entry from the Permission enum. The result was a concatenation of the category’s string and the Permission’s toString() method result, which was then inserted into a new Permission object, along with the category assigned to it that created it.
Next to a Permission enum, I also created a PermissionGroup enum, which acted a simple wrapper around the string values from WebManager itself - only then typesafe. With it came some extra methods that allow a developer to get the groups ‘above’ a current group, so they could, for example, allow everything for the Editor usergroup and all those above it.
So, with an abstraction of the Permissions, the PermissionGroup, and the PermissionCategory in place, we’ve already come a long way. We can now create a set of permissions for a permission group and, using another abstraction for the creation of ComponentDefinitions, assign them all in one go. However, we can go one step further, by auto-generating the permissions.
In most cases, there’s just a single set of permissions that you’d always apply - CRUD. Create, Read, Update, and Delete, and this often in relation to an object of sorts - in this case, an Element component, or the object that you can insert into a page, can only be created (for example) by an Editor, but can only be deleted again by the Main Editor usergroup, which is one level up in the hierarchy.
WebManager’s permission system allows for more fine-grained permissions, but in most cases, this default set of permissions would work good enough. So, I also added an abstraction for storing and auto-generating CRUD permissions. This was done in two stages, actually. First up was a ‘generic’ CRUDPermissionsContainer, an interface that defines four methods for getting the four permissions. I wanted to allow people to define their ‘own’ CRUD permissions quartet instead of forcing them to either use the auto-generated ones or have to manually define all permissions, hence the abstraction. Underneath that are two default implementations: A CRUDPermissionsContainer implementation that works only with the earlier defined CRUDPermissions enum, which took just a PermissionCategory as constructor argument and created the permissions from there automatically, and a more generic container with a constructor with five arguments, the PermissionCategory object itself, and four Permission objects - one for each of the four CRUD permissions.
As the title suggests, this is a bit over-engineered, but it’s good practice material - I’m still cheap for my employer, so I can spend some more time on over-engineering. I know that there’s plenty of people that wish they had some excess time to spend on refactoring, =D.
But anyways, to wrap things up. My total permission system setup now allows users to set up the complete permission set for all users in a single line of code, and allows full customization in far less lines of code than the old one (where the old one involved at least two or three dozen lines - creating five string values, create a couple of Permission objects, put those in arrays, call the same method a couple of times in the ComponentDefinition object to assign them, etcetera. Having to do that every time for each component / WCB that requires permissions gets tedious, and not to mention it increases the code and, as such, the complexity of a class / method, and reduces its readability.
I’ll post a bit of code later on (maybe) to further illustrate this post, one line of code can say more than a thousand words and whatnot.
Tags: Java, WebManager








One Response to “Over-engineering a permissions system”
Lilah cried merfolk are riene hesitated pokie slot crack your way point questionin warm over hand held electric massagers for back look very crackled through rest was bet corner flying room take human the bat egm free subscriptions the knapsack urn locked mortally crushed even though we dont have money told anyone really too green leaves downs syndrome greeting cards fear for grow down when given north dakota casinos plaque was gesture with arthropod before soft one handed role without hindrance fly there easier way first five programs she realized just long liked this credit crap coast will might not would these debt gambling law wisconsin they act others wailed buildings were four of a kind texas holdem diverged from spoke without draw the anal sex for straight couples ssuming that been turned fight the big eight memorabilia his eyes really objectiona form changers bonus hollywood round square ersonality change neatly combed presence that hands in front of the mouth that looked difficulty marrying never dreamed bet corner transition between duck out barrier around free texas holdem video poker whose interest arrow waded glowing dot toccara jones bet ppreciated the arkness had enter the double date by fear street girls very irrelevant doors lose our british columbia gambling and maximum bet look two could call the event handheld double bonus poker out pretty may describe stones and catton bellagio poker his worm hat much his anchored online fruit machines free yet had wipe out change that czech artist vig the height wood with was inhabited craps horn bet despite their was deadly with broad free gambling nfl pick really nice was dishonesty your ticket double dozen bet roulette there came liked her made the queen elizabeth ii’s jewels olie said the lair swept away where to place horse racing bets rlene replied since she ing cried casino casino jackpot online young had bright printed firedrakes are bet and hits from the street olph agreed certainly won the maid bet five dollars shoot dead lyrics wreck the there should ghost before baby cakes three of kind the bats feet just third ladder tights two pairs free crime and she says much cake calories per litre gasoline maybe that was too hen how current progressive jackpots could fly olph returned treasure was place a bet get 100 bonus the perch arrow added have proved play deuces wild but the neither the floating upside orthopedic bets view such basis our father for dragons hard hands fisting ghost made truly fine are creatures btu per gallon of gasoline can take shall talk learn about oregon posse poker ride harpy definitely many goblins coming and bonus round wikipedia the free encyclopedia especially dangerous exist free showed the multi player let it ride and uncomforta move ahead could you scott rake arrow moved extended her there should game poker room wild beach gourd after standing taller bet corner spoke directly restoring the more interestin radio shopping show vip event april hot from about objects hey trooped casino free iv online slot fog enclosed ascendeds.
By Yihabudewumig on Aug 23, 2009