Search code examples
javatapestry

Tapestry 5 URL manipulation


We have a ViewRecordScreen in our Tapestry5 application with a URL:

http://host:8080/app/viewRecord

To view a record from our search screen you simply click a page link. However if you right click the link and select 'Copy link address' you get:

http://host:8080/app/searchresults:viewRecord/12345678

I can now manipulate that url by updating the id to view other records. What is the best way to prevent URL manipulation in Tapestry 5 (I'm assuming I'll have to write some server-side validation code however I'm hoping Tapestry might have a litle something I'm unaware of that could assist.)

Thanks in advance.


Solution

  • As with any application, security is the developer's responsibility. You cannot trust a URL and you should always make sure a user is entitled to view / edit an entity rather than blindly letting them do it because the URL said so.

    As you are probably aware, Tapestry can automatically convert between clientside strings and serverside objects using ValueEncoders. If you use tapestry-hibernate it will automatically create ValueEncoders for all of your entities. Then, you can use entities as activation context or event context on the serverside and tapestry will generate URL's based on the id's.

    If you'd like a to intercept the coercion from string to serverside object, you may want to decorate the ValueEncoderSource with your own custom security checks. This will most likely look up the logged in user from the session.

    In my personal opinion, you shouldn't decorate the ValueEncoderSource. You should have services for getting and updating your entities. The services should take a User object as a parameter and should validate before the get / update. The User can be looked up from the session in you pages / components which pass through to the service layer.

    eg:

    public interface FooService {
        public Foo[] getAllFoos(User user);
        public Result updateFoo(User user, Foo foo);
        public Result createFoo(User user, Foo foo);
    }