I’m exploring a new pattern – I’m sure it’s been done before, but it’s new to me, and a useful exercise to get to the next stage with an application I’m envisioning. The pattern is using Seaside Decorators as security guards.
So, last night, finally squeezed in enough time to my decorator guards into action. Happy to report they’re working fine. You can review the demo app yourself at agoric.seasidehosting.st/seaside/ibis . Login as email@example.com, password bob, or firstname.lastname@example.org, password alice.
I’m not completely proud of this code – it’s a quick hack, needs some refactoring. And, cosmetics are not pretty – will need to do some CSS prettifying soon. The “guard” itself takes a traditional, ACL-lookup approach to security, and I’d like to refactor that to more of a capabilities approach, but ACLs work fine for now: straightforward, familiar and easy to understand. Here’s what the Guard itself look like:
WADecoration subclass: #IBSecEditGuard instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'IBIS' renderContentOn: html "if usr has access rights, render appropriate action buttons, then render object itself" html div class: 'editframe';style: 'margin-left: ',(self owner level *3) asString, 'em'; with: [ self userIsEditor ifTrue: [ html span class: 'cmd'; with: [ html anchor callback: [ self edit]; with: 'edit'.]]. html space. self renderOwnerOn: html] userIsEditor ^(self editorsfordoc contains: self session user) or: [self session user = self owner doc author] canedit ^(self allowededitors contains: self session user) editorsfordoc ^ IBSecGuard editorsfordoc: self owner doc edit self owner edit
To deploy the guard, add it as a decorator to an appropriate view, using addDecoration:.
IBISDocView>>initialize super initialize. myEditor := IBISDocumentEditor new. myLevel := 0. self addDecoration: IBSecEditGuard new. IBISDocView>>renderContentOn: html html span class: 'cmd'; with: [html anchor callback: [self answer: true]; with: 'back']. html div class: 'doc'; with: [html paragraph class: 'title'; with: [html text: myDoc type, ': ', myDoc title. html span class: 'author'; with: ' (',myDoc author userName,')']. html paragraph class: 'text'; with: [html text: myDoc text]. ].
So, the view here is not at all concerned with security. It renders the object (myDoc) visible, and has a pointer to the document’s editor view, but doesn’t involve itself in whether a user has edit access or not – that’s the Decorator’s job. Security, like persistence and logging, are typical application needs, and it’s nice to provide an external framework to provide those services, instead of intermingling security with presentation with business logic code. My demo here provides security with the one line addition of a Decorator object, and that object itself is just around 10 lines of code.
As I mentioned, this is still just a hack; there’s some refactoring that will be welcome, and I’ll likely abandon the ACL approach in favor of a more capabilities-oriented approach; and, I envision a more general way of visually adding “commands” (like the edit anchor link) to the Decorator view, in such a way that it can support multiple command links, in a chain of decorators … but this is a good start.