2 Replies Latest reply on Mar 9, 2007 11:22 AM by John Chesher

    Use of Seam Security/drools to selectively load a list?

    John Chesher Newbie

      I have an application where I want users to be able to add other new users IF the new user's role is "less than" that of the current user. By "less than" I mean that the user roles are hierarchical, as in the following roles hierarchy:

      Super Admin (can add users w/ role of "Company Admin" or "Client Admin")
       ===> Company Admin (can add users w/ role of "Client Admin")
       ===> Client Admin (cannot add users)


      So, on the "Add Users" page, I would like to load up a ListBox of possible roles for the new user with only the roles that the current user is permitted to add. Plus, I would like to do this in a way that is defined outside the Java code, to make maintenance easier, as lower level roles will change over time. I thought I would use drools/JBoss Rules to do this. Here's my code:

      This is the ListBox in the view:

      <h:selectOneListbox id="roleSelection" value="#{userRole.role}">
       <f:selectItems value="#{maintainUsersAndContacts.roleList}" required="true" />
      </h:selectOneListbox>



      Here is the method (in a session bean) that loads SelectItems into an array

      public ArrayList<SelectItem> getRoleList() {
       ArrayList<SelectItem> roleNames = new ArrayList<SelectItem>();
       ArrayList<UserRole> roles = (ArrayList<UserRole>) entityManager.createQuery("from UserRole").getResultList();
      
       for (UserRole r : roles) {
       if ( ( ! r.getDisabled()) && ( ! r.getRole().equals("Super Admin"))) {
       if (identity.hasPermission("user", "create", "false")) {
       roleNames.add(new SelectItem(r.getRole()));
       }
       }
       }
       return roleNames;
      }



      And here are my drools rules that would apply to this functionality: (Sorry if way off - I'm a drools newbie ;-)

      rule CanAddUserOfThisRole
       no-loop
       activation-group "permissions"
      when
       c: PermissionCheck(name == "user", action == "create", granted == false)
       Role(name == "Super Admin")
      then
       c.grant();
       modify(c);
      end;
      
      
      rule CanAddUserOfThisRole2
       no-loop
       activation-group "permissions"
      when
       c: PermissionCheck(name == "user", action == "create", granted == false)
       Role(usersRole : name)
       UserRole(newRole : role -> (newRole.getRole().equals("Client Admin") && usersRole.equals("Company Admin")))
      then
       c.grant();
       modify(c);
      end;


      I haven't finished this, as it also involves code changes that will ripple through my project, however, when I reached this point, I started wondering how drools was going to know what "Role" object I was referring to in the following section of the drools code:

      UserRole(newRole : role ->


      After reading the Security section of the Seam Ref Doc thoroughly, I am now guessing that I am trying to do something that is not possible using the current Seam-1.2-drools integration, but I thought I would reach out to the Seam community for opinions before I abandon the idea.

      Is this possible? If so, how do I go about it? Manually outject a Role object immediately before the permission check?

      If not possible as I proposed it, does anyone have another idea of how to implement? (Note, after previewing my own post, the idea came to me to put an indicator on the UserRole object indicating it's "place" within the hierarchy. So, if it can't be done with Drools somehow, I'll probably go that route...)
      Thanks

        • 1. Re: Use of Seam Security/drools to selectively load a list?
          Shane Bryzak Master

          You need to assert your UserRole object into the working memory for your permission check. You are calling hasPermission like this:

          identity.hasPermission("user", "create", "false")


          The third parameter is a varargs which can accept any number of objects that are asserted into the working memory, so instead you should be passing in the UserRole object:

          identity.hasPermission("user", "create", r)



          • 2. Re: Use of Seam Security/drools to selectively load a list?
            John Chesher Newbie

            Thanks Shane. As it turns out, I found a simpler way to implement this, by just passing the role name to the permission check in the "name" (1st) argument of hasPermission(). However, your response did help me to understand how to use the third argument, which is pretty cool and something I will no doubt be using later.

            In case it helps anyone else trying to implement something simliar, here is my revised code to load the SelectItems to be used in the view:

            The session bean method to determine which items should be in the list:

            public ArrayList<SelectItem> getRoleList() {
            
             ArrayList<SelectItem> roleNames = new ArrayList<SelectItem>();
            
             ArrayList<Role> roles = (ArrayList<Role>) entityManager.createQuery("from Role")
             .getResultList();
            
             for (Role r : roles) {
             if ( ! r.getDisabled()) {
             if (identity.hasPermission(r.getRole(), "create")) {
             roleNames.add(new SelectItem(r.getRole()));
             }
             }
             }
             return roleNames;
             }


            The drools rules that apply:
            rule CanAddCompanyAdmin
            when
             c: PermissionCheck(name == "Company Admin", action == "create")
             Role(name == "Super Admin")
            then
             c.grant();
            end;
            
            
            rule CanAddClientAdmin
            when
             c: PermissionCheck(name == "Client Admin", action == "create")
             Role(name == "Company Admin")
            then
             c.grant();
            end;