You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by Apache Wiki <wi...@apache.org> on 2008/03/11 13:58:24 UTC

[Tapestry Wiki] Update of "StephaneDecleire" by StephaneDecleire

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for change notification.

The following page has been changed by StephaneDecleire:
http://wiki.apache.org/tapestry/StephaneDecleire

New page:
##language:en
== Tapestry5HowToControlAccess ==
In the articles [http://wiki.apache.org/tapestry/Tapestry5HowToCreateADispatcher Tapestry5HowToCreateADispatcher] and [http://wiki.apache.org/tapestry/Tapestry5HowToCreateADispatcher2 Tapestry5HowToCreateADispatcher2], Chris Lewis has explained how to create a dispatcher, get it into the pipeline, and use it to check user rights against the url requested.
What i need in my project is similar but i would rather check the rights of my users against an information stored in the page requested, say an annotation !

=== Page rights as an annotation ===
Our first task is to create a @Private annotation that we will put on pages where the authentication of the user is required. Our annotation will be associated to pages and will have no parameters. So, its implementation will be as simple as :
{{{
@Target(TYPE)
@Retention(RUNTIME)
@Documented
public @interface Private
{
}
}}}

=== User rights in the user session ===
The state of the user will be stored in his session. To keep it simple, the status of the user will be "logged in" or "logged out". So the interface of the user session will display a function to get the user state :
{{{
public interface UserSession
{
  ...
  public abstract boolean isUserLoggedIn();
  ...
}
}}}

=== The problem ===
With those implementations in hand, what we have to do is to get the Tapestry page associated with the request of the dispatcher and check on this page the presence of the @Private annotation.

=== The solution ===
We will just have to parse the path of the request and check it against the Tapestry ComponentClassResolver service (like in the Tapestry PageRenderDispatcher) to find the page name. Having the page name, we can get the Tapestry page from the Tapestry RequestPageCache. After we get the Tapestry Page, we can check the presence of our @Private annotation :

{{{
public class AccessController implements Dispatcher
{
  private final static String LOGIN_PAGE = "/login";

  private ApplicationStateManager asm;
  private UserSessionImpl newUserSession;
  private final ComponentClassResolver resolver;
  private final RequestPageCache cache;

  /**
   * Receive all the services needed as constructor arguments. When we bind this
   * service, T5 IoC will provide all the services !
   */
  public AccessController(ApplicationStateManager asm, ComponentClassResolver resolver, RequestPageCache cache, UserSessionImpl newUserSession)
  {
    this.asm = asm;
    this.newUserSession = newUserSession;
    this.resolver = resolver;
    this.cache = cache;
  }

  public boolean dispatch(Request request, Response response) throws IOException
  {
    /* We need to get the Tapestry page requested by the user.
     * So we parse the path extracted from the request
     */
    String path = request.getPath();
    if (path.equals("")) return false;

    int nextslashx = path.length();
    String pageName;

    while (true)
    {
      pageName = path.substring(1, nextslashx);
      if (!pageName.endsWith("/") && resolver.isPageName(pageName)) break;
      nextslashx = path.lastIndexOf('/', nextslashx - 1);
      if (nextslashx <= 1) return false;
    }
    return checkAccess(pageName, request, response);
  }

  /**
   * Check the rights of the user for the page requested
   */
  public boolean checkAccess(String pageName, Request request, Response response) {

    boolean canAccess = true;

    /* Is the requested page private ? */
    ComponentSource cs = new ComponentSourceImpl(cache);
    Component page = cs.getPage(pageName);
    Boolean privatePage = Boolean.valueOf(page.getComponentResources().getComponentModel().getMeta("private"));
        
    if (privatePage)
    {
      canAccess = false;
      /* Is the user already authentified ? */
      if(asm.exists(UserSessionImpl.class))
      {
        UserSessionImpl userSession = asm.get(UserSessionImpl.class);
        canAccess = userSession.isUserLoggedIn();
      }
    }
        
    /* This page can't be requested by a non authentified user => we redirect him on the signon page */
    if(!canAccess) {
      response.sendRedirect(request.getContextPath() + LOGIN_PAGE);
    }
        
    return false;
  }
}
}}}

== Conclusion ==
We have made the choice to use an annotation to set the page status but after we get the Tapestry page in the dispatcher, any other information of the page can be checked.
An interesting evolution would be to keep the initial request in the user session to be able to redirect the user on it after he has logged in ...
Any suggestions, corrections, or other ideas on this document are welcome. Feel free to contact me on sdecleire@cariboo-networks.com (Stephane Decleire).

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