You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by "Robert J. Walker" <rw...@mshare.net> on 2007/01/30 00:48:26 UTC

Reading page specifications... *without* loading the page

My application has multiple security roles. To handle this, I have a ProtectedPage class that handles all the security stuff, and all pages that need to be secured descend from this class. It expects that the page specification have the following tag:

<meta key="roles" value="{list of role names}"/>

In the validate() method, it reads that role name list, checks to see if the user has any of those roles and acts accordingly. All this works fine.

The problem is, in my navigation I need to check each link to see if the user is allowed to navigate to that page, and hide the link if they aren't. This has two problems:

1) It has to load *all* the page specifications just to check one meta element on each. That sucks.

2) When page caching is enabled, it causes NullPointerExceptions since many of the pages require a reference to the request cycle to initialize themselves, which works fine when you're actually activating that page, but when you pull a page out of the pool without activating it, it often *won't* have a cycle.

So are there any ideas out there on how I can read a <meta> in a page specification *without* initializing the page? Even just the string value would suffice.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Reading page specifications... *without* loading the page

Posted by Sam Gendler <sg...@ideasculptor.com>.
We solved this a number of ways, depending upon particular context
within our app.  Acegi was unable to satisfy all of our security
requirements, so we went with a custom solution from top to bottom,
and one of our requirements was identical to yours.  The set of roles
and per-page permission for each role are loaded into a data structure
rather than parsed out of the page specification, in our case.  This
gives us the benefit of being able to use permissions without
redeploying the app.  You could choose to populate your data structure
via a declarative environment such as a spring context, hivemind
config, external config file, database, etc, so it is pretty flexible
in that regard.  In our case, the data structure is a spring bean
which is injected into the page and then passed into components via a
parameter.

Within tapestry, we implemented the following -

There's an AuthorizationDelegate injected into any page which is
accessed within the pageValidate method.  It checks the currently
logged-in user and its assigned roles against the roles allowed to
load the page (and in our case, a mode - read or write).  If they fail
auth, they are redirected away. Within templates, we use a tag
<IfAuth> which can conditionally include parts of a template based on
whether a user is authorized to see a section (we actually have
per-property r/w permissions on each entity, so every form field is
wrapped in an IfAuth tag, usually within a subclass of the original
tapestry component).  We have subclassed ExternalLink and PageLink so
that if the current user is not authorized, the link renders
differently (and we have various modes, depending upon context).  Our
IfAuth tag actually works much like if/elseif/else in that you can
cascade through conditionals depending upon how previous conditions
evaluated.  This allows us to have alternative renditions of a
template area based on granted permission.

Since we have read/write permissions on individual properties of
entities in the ui based on role, but we also have per-entity
read/write permissions assigned to individual users, we really weren't
able to use Acegi.  Acegi wanted us to do lots of things up in the
service layer that were far more effectively handled down in the data
mapping layer.  We use hibernate filters to ensure that only objects
assigned to the current user are loaded, modified, or stored.  We use
an AOP interceptor to inject the appropriate filters on any service
method calls.  All that necessitated a non-Acegi solution, which just
couldn't do what we wanted efficiently. By using filters and AOP and
subclassing various input field components, we were able to make very
minimal changes to the service or data access layers and kept changes
to our ui layer to a bare minimum (the entire security layer was added
on after initial application development, since it was not spec'd
before we had to have the first internal-use-only release out the
door).  I can think of cleaner solutions if I was building an app to
support that security model from scratch, but our solution wound up
being very flexible with minimal invasiveness into an existing app.

To be honest, the saving grace for our app was that, because we had
very consistent layout for each input component, we created a wrapper
component which would determine the type of input field to render
based on the type of the property that was bound to it (Kind of like
BeanForm, but for an individual property instead of an entire Bean,
giving us more control over layout and ajax fanciness).  Booleans get
checkboxes, lists get select drop downs or palettes, strings get
textboxes, etc.  This enabled us to just throw an IfAuth tag around
the entire template contents for the wrapper component in order to
conditionally include a field based on role permissions.  With that
single tag, we were able to apply role-based authorization to about
85% of our application.  Slapping IfAuth tags around individual menu
items in the main menu took us to about 95%.  The remaining 5%
consisted of fields which didn't use our wrapper component and
required individual IfAuth conditionals and links which were modified
to use subclass versions of the link components that conditionally
include the link depending upon authorization.  We are now free to
build a UI to modify the permissions data structure on the fly, which
is also very useful to our organization.

--sam



On 1/30/07, Hugo Palma <hu...@gmail.com> wrote:
> Ok. If you really want to go ahead with page spec parsing i guess you
> can use the servlet context to find the spec file and then you'll have
> to parse it yourself. You can inject the servlet context adding this to
> your pages base class:
>
> @InjectObject("service:tapestry.globals.ServletContext")
> public abstract ServletContext getServletContext();
>
>
>
> Robert J. Walker wrote:
> > Yeah, we've been considering Acegi, but that's a little more long-range. The only issue I have with using annotations for this is that I would have to create a class for every page in the app. As it stands right now, I'm able to reuse the same class for a fair number of my simpler pages without having a subclass for each one.
> >
> > Robert J. Walker
> >
> > -----Original Message-----
> > From: Hugo Palma [mailto:hugo.m.palma@gmail.com]
> > Sent: Monday, January 29, 2007 4:53 PM
> > To: Tapestry users
> > Subject: Re: Reading page specifications... *without* loading the page
> >
> >
> > Without really answering your question, have you looked at
> > tapestry-acegi (http://www.carmanconsulting.com/tapestry-acegi/).
> > The Secured annotation is a life saver......
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > For additional commands, e-mail: users-help@tapestry.apache.org
> >
> >
> >
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Reading page specifications... *without* loading the page

Posted by Hugo Palma <hu...@gmail.com>.
Ok. If you really want to go ahead with page spec parsing i guess you 
can use the servlet context to find the spec file and then you'll have 
to parse it yourself. You can inject the servlet context adding this to 
your pages base class:

@InjectObject("service:tapestry.globals.ServletContext")
public abstract ServletContext getServletContext();



Robert J. Walker wrote:
> Yeah, we've been considering Acegi, but that's a little more long-range. The only issue I have with using annotations for this is that I would have to create a class for every page in the app. As it stands right now, I'm able to reuse the same class for a fair number of my simpler pages without having a subclass for each one.
>
> Robert J. Walker
>
> -----Original Message-----
> From: Hugo Palma [mailto:hugo.m.palma@gmail.com] 
> Sent: Monday, January 29, 2007 4:53 PM
> To: Tapestry users
> Subject: Re: Reading page specifications... *without* loading the page
>
>
> Without really answering your question, have you looked at 
> tapestry-acegi (http://www.carmanconsulting.com/tapestry-acegi/).
> The Secured annotation is a life saver......
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
>   

RE: Reading page specifications... *without* loading the page

Posted by "Robert J. Walker" <rw...@mshare.net>.
Yeah, we've been considering Acegi, but that's a little more long-range. The only issue I have with using annotations for this is that I would have to create a class for every page in the app. As it stands right now, I'm able to reuse the same class for a fair number of my simpler pages without having a subclass for each one.

Robert J. Walker

-----Original Message-----
From: Hugo Palma [mailto:hugo.m.palma@gmail.com] 
Sent: Monday, January 29, 2007 4:53 PM
To: Tapestry users
Subject: Re: Reading page specifications... *without* loading the page


Without really answering your question, have you looked at 
tapestry-acegi (http://www.carmanconsulting.com/tapestry-acegi/).
The Secured annotation is a life saver......


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Reading page specifications... *without* loading the page

Posted by Hugo Palma <hu...@gmail.com>.
Without really answering your question, have you looked at 
tapestry-acegi (http://www.carmanconsulting.com/tapestry-acegi/).
The Secured annotation is a life saver......

Robert J. Walker wrote:
> My application has multiple security roles. To handle this, I have a ProtectedPage class that handles all the security stuff, and all pages that need to be secured descend from this class. It expects that the page specification have the following tag:
>
> <meta key="roles" value="{list of role names}"/>
>
> In the validate() method, it reads that role name list, checks to see if the user has any of those roles and acts accordingly. All this works fine.
>
> The problem is, in my navigation I need to check each link to see if the user is allowed to navigate to that page, and hide the link if they aren't. This has two problems:
>
> 1) It has to load *all* the page specifications just to check one meta element on each. That sucks.
>
> 2) When page caching is enabled, it causes NullPointerExceptions since many of the pages require a reference to the request cycle to initialize themselves, which works fine when you're actually activating that page, but when you pull a page out of the pool without activating it, it often *won't* have a cycle.
>
> So are there any ideas out there on how I can read a <meta> in a page specification *without* initializing the page? Even just the string value would suffice.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
>