Sam, I finally read the full text of your message. :-)
There is huge overlap between your requirements and mine. My application also had the issue that role-based security was not sufficient. I used a custom imlementation of the Acegi AclProvider to control (on a per-entity basis) how much could be seen or if links were generated to access certain records. This could be used in addition to, or in place of, the role-based access. I didn't need to filter result sets as was your case. I would be very interested in seeing what you have put together. Apart from the authorization issues, I have yet to see a nice performant Hibernate table model. This thread has prompted me to start cleaning up my code and packaging it into a library. With the carmenconsulting page-level security option on one end, role and instance-based acl security with my work, and your work including hibernate-level collection filters there could be a great set of options for securing tapestry apps. Jonathan On 2/27/07, Sam Gendler <[EMAIL PROTECTED]> wrote:
It is simple enough to build a component based on the @If component which will conditionally check some authorization requirement. That's what we have for handling role based auth in a template, including some sophisticated else handling which lets the template cascade through a number of options. We don't explicitly list roles anywhere in the templates. We have a delegate that maps permissions from roles to objects. Our @IfAuth component just checks whether the current user has a particular permission (read, write, and deny basically). We've actually got permissions assigned on a per-property basis on many objects, so we also have wrapper components which wrap the normal form components with the IfAuth conditional so that our templates aren't full of difficult-to-read conditional blocks. The entire chain of possible permissions are represented in a single component, so if they have write permission, they will see a text box, read permission will show a label, deny will show a blank space, etc. We actually went a step further and built a single component which renders any number of form components based on the type of the value being assigned. Booleans get checkboxes, lists get palettes, strings get text fields, numbers get text fields + number translator, etc. Each also takes care of rendering correctly according to the permission available to the current user for the field in question. It is similar to bean form, but pre-dates it by quite a bit. We do have an IfRole component for the few places where we have to check whether a user is a particular role, such as when deciding whether to render a particular menu item. All of this could plug into Acegi or any kind of authorization mechanism you might care to roll into your app. So long as you can define some kind of AuthorizationDelegate that you can provide to the tags for doing the auth and returning a permission, it is pretty easy to implement and/or modify the auth mechanism. We also have record based security which is implemented entirely via hibernate filters and AOP interception which ensures that none of the service methods can be executed without having the appropriate hibernate filters enabled. This was necessary in order to handle things like tables with paging. The acegi mechanisms don't appear to provide a way to ensure that db queries only return the rows for which the current user is authorized, so offset/limit queries don't work correctly when acegi removes items after the query has run. This breaks the paging in the tables. So we use hibernate filters to ensure that any query that runs only ever returns the results appropriate for the current user. I'm intending to write a paper about this mechanism that folks can see, as it turned out to be incredibly flexible and very efficient. It's got unix filesystem style permissions (owner, group, world - although it is actually a little more sophisticated than that) and multiple permissions that can be applied to each (read, write, reassign). It also provides hierarchical auth, so you have the same permissions (or better) as any user below you in the hierarchy - allowing managers to have the same access as their direct reports, without explicitly assigning them to each record owned by a direct report. This is vital if any user might ever be moved within the organization. It also allows temporary owner reassignment without removing the original owner assignment. This allows employees to be assigned to cover for others during vacations and such without forcing the system to explicitly remember who used to be assigned where and then reassigning at the end of the period. The whole thing is completely transparent outside of the service layer. The DAO layer knows absolutely nothing about the authorization filters and neither does the ui layer (except, of course, where we've exposed fields you can edit to modify assignments and such). Even our service layer was almost entirely unchanged, since all filters and other auth checks are applied in an AOP interceptor. Basically, we modified the hibernate mapping docs to add the filters, added interceptors on the service methods in our spring config, and modified the schema to add the necessary new tables (no changes were necessary to the entity tables themelves, but new relations were added). It took a fair amount of research to get the design right, but actual implementation was surprisingly easy, especially considering that we had never explicltly implemented a hibernate filter or an AOP interceptor prior to implementing the row level auth mechanism. Once we got the db config dialed in, it only adds about 20% to the worst queries in the system and is usually much better than that. If there's interest in the details, let me know. Maybe that will motivate me to write the thing up properly. We had code freeze on Friday, so I'm just catching my breath from the effort of the release now. Here's the basic list of requirements we had to meet: * Role based authorization on each page (this already existed in our app) * Role based authorization on each property of any domain object (already in app) * User based authorization on a per-record basis * Actual auth is intersection of role and record auth. If user has write access to an entity, they still can only write the fields that roles they are assigned to have write permission on. * Must have hierarchical record-level auth (but not hierarchical role assignment) * Must be able to assign a user to cover another and then restore back to original state without having to externally track what original state was. Also, if original owner signs on from vacation, they should still have access (usually) * Must be able to assign record level auth to groups of users as well as individuals (also have world assignment, but that is really just a special group in our implementation) * Must have multiple 'owners' on any entity (sales maneger, account manager, external user, etc), each of whom shares the 'owner' permission * Must have ability to assign read, write, and reassign permission independantly to each of owners, group, and world. Engineering requirements included: * hierarchy to be dynamically computed rather than manually adding users to entities based on hierarchy. * minimize changes to existing code * must not break any existing functionality like table paging or lazy loading of collections * Allow for each owner to have different permission instead of sharing single owner permission. I know they will ask for it, even if they don't. Amazingly, despite extreme misgivings about delivering all of this functionality along with acceptable performance, I was able to concoct a mechansim that did all this. I really had my doubts right up until I finished my last experiment prior to writing up the design. --sam On 2/27/07, Jonathan Barker <[EMAIL PROTECTED]> wrote: > Mark, > > Do a Google search using the search string: > > site:http://mail-archives.apache.org/mod_mbox "Jonathan Barker" > > I posted some information and code in June 2006 about creating @Authorize > and @AclAuthorize based on the code for the tapestry @If component, and the > Authorize and AclAuthorize JSP taglibs. > > I've had this in production since last May and it's been working > beautifully. > > Jonathan > > > > -----Original Message----- > > From: Borut BolĨina [mailto:[EMAIL PROTECTED] > > Sent: Tuesday, February 27, 2007 12:31 PM > > To: Tapestry users > > Subject: Re: Role based security > > > > Hello Mark, > > > > Mark Stang wrote: > > > Ignore the Mediator class it is one of ours. The real logic is in the > > else. We store user and role in the visit and check when needed. > > > > > > > > > hth, > > > > > sorry, but it doesn't. I am looking for a more general solution - if at > > all exists. I wish to lay grounds for security in my Tapestry app beyond > > those described in Kent's book EWDT, Tapestry 101 or Beginning POJOS > > (Novice to Professional). Imagine a portal with several portlets. Each > > of the portlet is visible and/or editable only to some roles. In a > > portal server such as Liferay or JBoss Portal you can do this by > > assigning certain rights to portlets. I don't want to make a portal(!), > > but I want to have blocks of code on a Tapestry page protected with a > > pluggable authorization/authentication mechanism (memory based, LDAP, > > JDBC, maybe even Active Directory). > > > > Cheers, > > Borut > > > Mark > > > > > > Mark J. Stang > > > Senior Engineer/Architect > > > office: +1 303.468.2900 > > > mobile: +1 303.507.2833 > > > Ping Identity > > > > > > > > > > > > -----Original Message----- > > > From: Borut Bolcina [mailto:[EMAIL PROTECTED] > > > Sent: Tue 2/27/2007 7:08 AM > > > To: Tapestry users > > > Subject: Role based security > > > > > > Hello list, > > > > > > I was wondering if there is a better way of securing page components > > > than using @If components (example from VirtualLibrary for Tapestry > > > v4.0, Border.html) > > > > > > <span jwcid="@If" condition="ognl:admin"> > > > <tr> > > > <td rowspan="1" colspan="1" width="178" height="19"><img > > > src="/vlib/images/nav/nav_6x1.png" width="178" height="19" border="0" > > > alt="Admin"/></td> > > > </tr> > > > ... > > > </span> > > > > > > <span jwcid="@If" condition="ognl:loggedIn"> > > > <tr> > > > <td rowspan="1" colspan="1" width="178" height="29"><a href="#" > > > jwcid="logout"><img jwcid="logoutRollover" > > > src="/vlib/images/nav/nav_10x1.png" width="178" height="29" border="0" > > > alt="Logout"/></a></td> > > > </tr> > > > </span> > > > > > > <span jwcid="@If" condition="ognl:!loggedIn"> > > > <tr> > > > <td rowspan="1" colspan="1" width="178" height="29"><a href="#" > > > jwcid="login"><img jwcid="loginRollover" > > > src="/vlib/images/nav/nav_10x1.png" width="178" height="29" border="0" > > > alt="Login"/></a></td> > > > </tr> > > > </span> > > > > > > > > > I read all I could find on the list about acegi and a wiki entries > > > starting at http://wiki.apache.org/tapestry/AcegiSpringJava5, but none > > > of the texts mention or suggests something like > > > > > > <span jwcid="@Secured" role="acegi:{ROLE_USER, ROLE_ADMIN}"> > > > <tr> > > > <td rowspan="1" colspan="1" width="178" height="19"><img > > > src="/vlib/images/nav/nav_6x1.png" width="178" height="19" border="0" > > > alt="Admin"/></td> > > > </tr> > > > ... > > > </span> > > > > > > How about creating such component? How do you guys do it? > > > > > > Cheers, > > > Borut > > > > > > > > > --------------------------------------------------------------------- > > > To unsubscribe, e-mail: [EMAIL PROTECTED] > > > For additional commands, e-mail: [EMAIL PROTECTED] > > > > > > > > > > > > > > > > > > --------------------------------------------------------------------- > > To unsubscribe, e-mail: [EMAIL PROTECTED] > > For additional commands, e-mail: [EMAIL PROTECTED] > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > >
-- Jonathan Barker Consultant