Jim,

I have a T4 application that uses domain-object level security implemented
using the Acegi framework.  I have used custom authorization code more
appropriate for my task, rather than the built-in Acegi method.

It works beautifully, and I've certainly seen people attempting to access
things they shouldn't.

Jonathan
 

> -----Original Message-----
> From: Jim [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, April 22, 2008 10:08 PM
> To: Tapestry users
> Subject: Re: T5: Forms - Best Practice
> 
> Hi Christoph,
> 
> I know you're mostly asking about best-practice of process rather than
> security, but I think it's nonetheless important to bring up the issues
> that can arise when embedding primary keys of your entities client-side.
> 
> I'm still a T4 user, but when you say "a PageLink on a PersonSearch
> page, which has the Person's primary id as context", I assume that's
> analogous to the "parameters" attribute on a DirectLink in T4, in that
> the parameter is embedded in the page.  Even if that's not the case,
> I'll continue anyway :P
> 
> Building on your example, let's say that the logged-in user should only
> be able to search/edit people within his/her department.  If we're only
> passing the PersonID to the PersonEdit page, and that ID is embedded in
> each rendered link on the PersonSearch page output, then the user could
> hack the form/link from the PersonSearch page to pass an arbitrary
> PersonID to PersonEdit, potentially giving the user the ability to
> perform unauthorized edits.
> 
> I've started taking the approach of embedding not the ID, but a piece of
> information that's unique within the security-context (by
> "security-context", in this case I mean "department").  In this case,
> assuming that a person's full name is unique within a department, we
> could embed the person's full name into the PageLink, and the PersonEdit
> page would search not on the primary key of the person, but instead on
> the combination of the DepartmentID (retrieved from the session if we're
> keeping a User object in the session) and the full name we passed in.
> Since we're using the DepartmentID from the session, then the user can
> hack the form/link all he/she wants, and the best they'll do is bring up
> the editing form for someone that wasn't in the search results but is
> still in their department, so it'd still be an authorized action.
> 
> This sort of approach is annoying, because we'd love to be cleanly using
> solid efficient primary keys, but it probably pays to be paranoid.
> Anyone have a better approach on this issue?  Particularly with regard
> to search pages?
> 
> Jim
> 
> 
> Christoph Jäger wrote:
> > Hi,
> >
> > Sorry for this long post. I spent quite some time now to try to figure
> > out how to use forms to edit/update objects the "right" way (you know,
> > simple, stable, elegant, easy to read, easy add things, ...). I use
> > Tapestry 5.0.11. I am almost satisfied with what I came up with now,
> > but some improvements need to be done. Maybe someone on this list can
> > help with some ideas.
> >
> > As an example, lets have a PersonEdit page, with a PersonDao injected.
> > You can create new Person entries or edit existing ones. To edit an
> > existing person, there is a PageLink on a PersonSearch page, which has
> > the Person's primary id as context. To create a new Person, a PageLink
> > with 0 as context is used. To make this work, we have onActivate() and
> > onPassivate() methods in PersonEdit:
> >
> > void onActivate(int id)
> > {
> >   _id = id;
> >   if (id == 0)
> >   {
> >     _person = new Person();
> >   }
> >   else
> >   {
> >     _person=personDao.get(id);
> >   }
> > }
> >
> > int onPassivate()
> > {
> >   return _id;
> > }
> >
> > This way we can avoid using @Persist on the Person property (because,
> > for instance, we want a user to be able to open two browser windows,
> > viewing two different Person entries side by side and edit and save
> > both of them. I think this would be problematic if we use @Persist,
> > but please correct me if I am wrong).
> >
> > Now, editing an existing user works like this:
> >
> > - click the "edit user XYZ" PageLink on the PersonSearch page
> > - in onActivate(), the personDao is used to query the Person from the
> > database
> > - an HTML form is rendered to let the user edit the values
> >
> > Up to here everything looks perfect.
> >
> > - the user edits the Person's data and hits the "save" button
> >
> > - onActivate() is called, a fresh Person is loaded from the database
> > - for each field in the HTML form, validation is done (if defined),
> > and a property in the fresh Person instance is set if the validation
> > was successful
> > - onValidateForm() is called if existing to allow for cross-field
> > validation
> > - if all validations were successful, onSuccess() is called. Here we
> > call _person=personDao.save(_person). This save method returns a new
> > Person instance, exactly as it was written to the database (primary id
> > may be generated by the database, time stamps or version numbers
> > updated, ...). We use this new Person's id : _id=_person.getId() to
> > make sure we have the correct if for the next onPassivate()
> > - onPassivate() is called
> > - result sent to browser, redirect
> > - onActivate() loads Person again
> > - new form is rendered
> >
> > This is good, but I think it could be improved.
> >
> > 1. The Person is loaded from the database twice (using
> > personDao.get()), and saved once. The save() method of personDao
> > already gives us a new, fresh instance of Person, it seems like a
> > waste to load it again after the redirect.
> >
> > 2. During validation, we check if there is already a Person with the
> > same userid (in onValidateForm(), or in onValidateFromUserId()) and
> > warn the user if this is the case. But what happens if a new Person
> > with this userId is added just after onValidateForm() is called, but
> > before onSuccess() is called, where we want to save? To make our
> > program solid, we have to take this into account. In case save() does
> > not work, we do not want to see some exception page, but the form, as
> > it was filled, with a hint what might have gone wrong, so the user can
> > try again. To make this possible, we have to move the save() to
> > onValidateForm(), because there we can still record form errors (I
> > think there is a JIRA for an improvement to this situation).
> >
> > 3. We want to give the user feedback of what happened. After clicking
> > the save button, we want to show a message like "Successfully saved
> > new person information" above the form (at the same place you would
> > see error messages like: "The first name is mandatory"). The only
> > thing that comes to my mind is to use @Persist to save the message
> > from the onSuccess() or onValidateForm() through the redirect to the
> > next page render. But now I have problems to make sure this
> > @Persist'ed message is cleared and is only presented to the user
> > directly after the save button was clicked.
> >
> >
> > I think to find a nice solution for these issues (you know, easy
> > things should be easy to do, and a form like this does not sound very
> > complex to me, so there should be an easy solution), a @Persist, which
> > persists values just through the redirect would be very helpful. The
> > problem is, I have no idea how this could work. But maybe an option
> > like this already exists (I am sure I am not the first to have
> > problems like this), and I just didn't find it.
> >
> > Any ideas are welcome,
> >
> > Thanks,
> >
> > Christoph Jäger
> >
> >
> >
> > ---------------------------------------------------------------------
> > 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]

Reply via email to