Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » scout » fine-grained access control
fine-grained access control [message #1517387] Fri, 19 December 2014 13:10 Go to next message
Bertin Kiekebosch is currently offline Bertin KiekeboschFriend
Messages: 330
Registered: August 2011
Senior Member
Hi,

i am using fine-grained access control. This works nicely at the server side. When the user (Medewerker) executes the MedewerkerService.store method the permission is checked and the method is only allowed when he tries to save his own record.

  @Override
  public MedewerkerFormData store(MedewerkerFormData formData) throws ProcessingException {
    if (!ACCESS.check(new MedewerkerBewerkenPermission(formData.getMedewerkerNr()))) {
      throw new VetoException(TEXTS.get("AuthorizationFailed"));
    }


But when I use the permission at the client side it does not work. The fields and button of the form are always disabled.

  public class ModifyHandler extends AbstractFormHandler {

    @Override
    public void execLoad() throws ProcessingException {
      IMedewerkerService service = SERVICES.getService(IMedewerkerService.class);
      MedewerkerFormData formData = new MedewerkerFormData();
      exportFormData(formData);
      formData = service.load(formData);
      importFormData(formData);
      setEnabledPermission(new MedewerkerBewerkenPermission(formData.getMedewerkerNr()));
    }


Any idea what is going wrong or can't I use fine grainde permissions at the client side?
Regards Bertin


public class MedewerkerBewerkenPermission extends BasicHierarchyPermission {

  private static final long serialVersionUID = 0L;
  public static final int LEVEL_PERSOONLIJK = AutorisatieNiveauPersoonlijkCode.ID.intValue();
  public static final int LEVEL_VESTIGING = AutorisatieNiveauVestigingCode.ID.intValue();
  public static final int LEVEL_RID = AutorisatieNiveauRidCode.ID.intValue();

  private Long m_medewerkerNr; // medewerkerNr van ingelogde MPX medewerker

  public MedewerkerBewerkenPermission(Long medewerkerNr) {
    super("MedewerkerBewerkenPermission", LEVEL_UNDEFINED);
    m_medewerkerNr = medewerkerNr;
  }
...
...
Re: fine-grained access control [message #1523046 is a reply to message #1517387] Mon, 22 December 2014 17:59 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1243
Registered: October 2011
Senior Member
I am not able to test/debug it without you implementation of MedewerkerBewerkenPermission. Can you provide something? (The real code or if you prefer some dummy-logic that is near from real case enough)
Re: fine-grained access control [message #1524208 is a reply to message #1523046] Tue, 23 December 2014 09:39 Go to previous messageGo to next message
Bertin Kiekebosch is currently offline Bertin KiekeboschFriend
Messages: 330
Registered: August 2011
Senior Member
Hi,

hereby the complete code of MedewerkerBewerkenPermission. It checks for three levels. If LEVEL_PERSOONLIJK (Personal) a user can only change his own record. If LEVEL_VESTIGING (Department) a user can change records of employees in the same department and LEVEL_RID or LEVEL_ALL the user can change all records.

I noticed that the code on the server is only called once when invoked from the client and then cached. So if a user with LEVEL_PERSOONLIJK first opens his own record, permission is granted and stays granted. If a user first opens someone elses record permission is denied and stays denied.

I also noticed in the example on the wiki that in the constructor of the permission the id is added to the name but I cannot make that work either.

At the server side everything works OK.

public class MedewerkerBewerkenPermission extends BasicHierarchyPermission {

  /**
   * @param name
   */
  public MedewerkerBewerkenPermission() {
    super("MedewerkerBewerkenPermission");
  }

  private static final long serialVersionUID = 0L;
  public static final int LEVEL_PERSOONLIJK = AutorisatieNiveauPersoonlijkCode.ID.intValue();
  public static final int LEVEL_VESTIGING = AutorisatieNiveauVestigingCode.ID.intValue();
  public static final int LEVEL_RID = AutorisatieNiveauRidCode.ID.intValue();

  private Long m_medewerkerNr; // medewerkerNr van ingelogde MPX medewerker

  public MedewerkerBewerkenPermission(Long medewerkerNr) {
    super("MedewerkerBewerkenPermission", LEVEL_UNDEFINED);
    m_medewerkerNr = medewerkerNr;
  }

  @Override
  protected boolean execCheckLevel(int userLevel) throws ProcessingException {
    if (LEVEL_PERSOONLIJK == userLevel) {
      if (SERVICES.getService(IMedewerkerService.class).isEigenMedewerkerRecord(getMedewerkerNr())) {
        return true;
      }
    }
    if (LEVEL_VESTIGING == userLevel) {
      if (SERVICES.getService(IMedewerkerService.class).isEigenVestigingRecord(getMedewerkerNr())) {
        return true;
      }
    }
    if (LEVEL_RID == userLevel || LEVEL_ALL == userLevel) {
      return true;
    }
    return false;
  }

  public Long getMedewerkerNr() {
    return m_medewerkerNr;
  }
}

Re: fine-grained access control [message #1541624 is a reply to message #1524208] Fri, 02 January 2015 06:05 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1243
Registered: October 2011
Senior Member
I do not know Permissions well. I have tried to reproduce your setup...
In my client, execCheckLevel is never called (I have a break point in this method).

The first question I have is: how does your AccessControlService look like?
=> I assume you put in the Permissions object, one instance of the MedewerkerBewerkenPermission with the id (medewerkerNr) of the logged in user.

I also need to check this LEVEL stuff... I do not see where you set the required level in a form.

Have you some pointers on BasicHierarchyPermission? Do they exist? Otherwise this is a domain where we need to create some documentation.
Re: fine-grained access control [message #1541801 is a reply to message #1541624] Fri, 02 January 2015 08:25 Go to previous message
Chris Monty is currently offline Chris MontyFriend
Messages: 8
Registered: January 2015
Junior Member
Maybe I can help. Just as a point of clarification, from reading your description it sounds to me like you don't need to be using "fine-grained" access control, but rather standard hierarchical controls. Fine-grained is where you allow access per object, and then every time you check for access, you ask "Can this user read the object with this id?" (very fine-grained). With hierarchical you're just asking "Can the user read objects at this security level?".

In your example, the behaviour is correct I think. The user's access level is loaded on startup, and does not change, so the result of execCheckLevel can be cached (and doesn't need to be called again). You need to shift the level-checking mechanism to outside of the permission object.

I use hierarchical access control. In addition to the inherited levels LEVEL_UNDEFINED(-1), LEVEL_NONE(0) and LEVEL_ALL(100), I use LEVEL_OWN(10) and LEVEL_GLOBAL(20). In my database, each Unit object has a visibility setting which determines if only its owner (current user is object's creator and has LEVEL_OWN access level) can access it, or whether all users with the LEVEL_GLOBAL permission can access it. My permission code is thus:
import org.eclipse.scout.rt.shared.security.BasicHierarchyPermission;

public class ReadUnitPermission extends BasicHierarchyPermission {

  /**
   * Can read own entries.
   */
  public static final int LEVEL_OWN = 10;

  /**
   * Can read global entries.
   */
  public static final int LEVEL_GLOBAL = 20;

  private static final long serialVersionUID = 0L;

  public ReadUnitPermission() {
    super("ReadUnit", LEVEL_OWN);
  }
}

Note that you set the "required" permission level in the constructor. In my case above, the default required permission level is "LEVEL_OWN". What's also important is that the permission level ids increase in value, so in my example LEVEL_UNDEFINED(-1) < LEVEL_NONE(0) < LEVEL_OWN(10) < LEVEL_GLOBAL(20) < LEVEL_ALL(100). When I want to know if the user has the permission, I can write:
ACCESS.getLevel(new ReadUnitPermission()) >= LEVEL_OWN

If I want to show filter out 'hidden' objects in an outline, I use this SQL select:
DB.selectInto(""
          + "SELECT UNIT_NR, "
          + "       NAME, "
          + "       LAST_MODIFIED,"
          + "       SHARE_LEVEL "
          + "  FROM UNIT "
          + " WHERE UNIT_NR IN :unitNrs "
          + "   AND ((:permissionLevel = 100) OR (:permissionLevel >= 20 AND SHARE_LEVEL = " + PublicCode.ID + ") OR (:permissionLevel >= 10 AND SHARE_LEVEL = (" + PrivateCode.ID + ") AND USER_NR = :userNr)) "
          + "  INTO :{unit.unitNr}, "
          + "       :{unit.name}, "
          + "       :{unit.lastModified},"
          + "       :{unit.shareLevel} "
          , formData
          , new NVPair("permissionLevel", ACCESS.getLevel(new ReadUnitPermission()))
          );

Also note, if you look at the javadoc for AbstractSqlService.execCustomBindFunction() it hints that there is standard bind support for checking permission levels using statements like:
::level(ReadUnitPermission)

I haven't tested this myself, but it might work.
Previous Topic:sql replace function for derby
Next Topic:Dynamically generating menus
Goto Forum:
  


Current Time: Mon Oct 23 17:29:38 GMT 2017

Powered by FUDForum. Page generated in 0.03257 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software