0 Replies Latest reply on Sep 22, 2012 1:45 PM by demetrio812

    Seam Security - Authorization doesn't work (with workaround)

    demetrio812 Apprentice


      I've followed the Seam 3 guide to add Authorization check using Seam Security, basically I have a custom @Admin annotation and I applied in Pages.java to avoid unauthorized access to the administration by users without the "admin" role.


      If in the page I want to protect I add a viewAction, the system works as expected, if in the page I don't have any "page action" the system doesn't work.


      Basically I debugged the Seam Security code and I have noticed that it correctly intercepts the annotation, calls the authorizer and correctly calls the redirectToAccessDeniedView() method in SecurityPhaseListener, the problems start here:




          private void redirectToAccessDeniedView(FacesContext context, UIViewRoot viewRoot) {

              // If a user has already done a redirect and rendered the response (possibly in an observer) we cannot do this output

              final PhaseId currentPhase = context.getCurrentPhaseId();

              if (!context.getResponseComplete() && !PhaseId.RENDER_RESPONSE.equals(currentPhase)) {

                  AccessDeniedView accessDeniedView = viewConfigStore.getAnnotationData(viewRoot.getViewId(), AccessDeniedView.class);

                  if (accessDeniedView == null || accessDeniedView.value() == null || accessDeniedView.value().isEmpty()) {

                      log.warn("No AccessDeniedView is configured, returning 401 response (access denied). Please configure an AccessDeniedView in the ViewConfig.");





                  String accessDeniedViewId = accessDeniedView.value();

                  log.debugf("Redirecting to configured AccessDenied %s", accessDeniedViewId);

                  NavigationHandler navHandler = context.getApplication().getNavigationHandler();

                  navHandler.handleNavigation(context, "", accessDeniedViewId);






      As you can see it goes on only if getResponseComplete()==false and we aren't in the RENDER_RESPONSE phase. If I directly access that page by writing it to the browser URL (or with a redirect) JSF goes directly to the RENDER_RESPONSE phase so the method above skips the redirect. In case I add the viewAction the INVOKE_APPLICATION view is called and everything works.


      My workaround is to add @RestrictAtPhase(PhaseIdType.RESTORE_VIEW) to the annotation so that it gets called at the RESTORE_VIEW phase anyway, so that's the code:






      @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})


      public @interface Admin { }



      I don't think there are problems with this approach except if we need to run some action before the check...


      Any hints?


      Btw I think that Seam 3 need at least other 2 minor version updates to address at least the problems fixed by the community, I'm going to open another post about that topic.


      Demetrio Filocamo