Hi Ian,
Sorry for the delay of updating the thread. I had to to some
experiment(writing dummy tests iteratively) to figure out what you exactly
meant. And finally was able to implement what you said. I have commited the
src under a new package called "security". Currently it is a util class
which is executable and we can test.
Now i.e following can be done and returns accurate results.
String path = "/content/cassandra/p2/c2";
String policy="0_dishara_allow :0x01 ";
accessControlUtil.addACE(path,policy);
int results[] = accessControlUtil.buildAtLevel(0x04,path);
System.out.println("GRANT" +results[0]);
System.out.println("DENY" +results[1]);
On Mon, Sep 16, 2013 at 2:28 PM, Ian Boston <[email protected]> wrote:
> Hi,
>
> Yes you could store the ACL (ordered list of ACE's) with the resource
> itself, although you will then have to add additional code to protect
> access to that property which will complicate the CassandraProvider,
> which is why I was sugesting that you do ACL storage in a completely
> separate Column Family.
>
> If you choose to do it that way (storing ACLs with the resource), then
> you might consider storing the ACL as a JSON string.
>
> By default, permissions inherit from the permissions on the parent
> resource, so there is no need to create an ACL on creation, but the
> implementation of the ResourceAccessGate will need compute access
> control including parent ACLs.
>
> How you implement ACL crud is entirely upto you. I suggest you use
> Hector directly to do this.
>
> This will make your CassandraResourceAccessGate completely separate
> from you CassandraResourceProvider.
>
> Best Regards
> Ian
>
> On 13 September 2013 13:21, Dishara Wijewardana <[email protected]>
> wrote:
> > On Thu, Sep 12, 2013 at 8:37 PM, Ian Boston <[email protected]> wrote:
> >
> >> Hi
> >>
> >> On 12 September 2013 13:24, Dishara Wijewardana <
> [email protected]>
> >> wrote:
> >> > Hi Ian
> >> >
> >> >
> >> > On Thu, Sep 12, 2013 at 1:50 PM, Ian Boston <[email protected]> wrote:
> >> >
> >> >> Hi Dishara,
> >> >> To make the Cassandra Resource Provider really useful I think we need
> >> >> to add access control. I think the best way of doing this is to
> borrow
> >> >> some concepts from Jackrabbit access control.
> >> >>
> >> >>
> >> > The following algorithms, and etc does sling already have any
> >> > implementation of it. If so I can reuse them. Since sling has few
> >> providers
> >> > I believe they probably have some common interface.
> >>
> >>
> >>
> >> There is not, or at least, not in a way that is exposed. There is an
> >> implementation inside Jackrabbit, but it is tightly coupled to
> >> Jackrabbit and more complex than the simple system below.
> >>
> >> Once implemented, this access control system may be exposed as a
> >> ResourceAccessGate, but since (IIRC) imposing anything other than read
> >> access control has not been done, the CassandraResourceProvider may
> >> use the implementation directly to impose write and delete.
> >>
> >> >
> >> >
> >> >> Take a deep breath, and you will see why I left this till last.
> >> >>
> >> >> I think we should provide path base access control, which inherits
> >> >> from parent resources in the path. At every level there is a an
> >> >> ordered list of access control entries each access control entry
> (ACE)
> >> >> being either an allow entry or a deny entry. What is allowed or
> denied
> >> >> is defined in a 32bit bitmap with each bit representing 1 permission,
> >> >> so we can have upto 32 permissions. Each ACE specifies a single
> >> >> principal. So an ACL consists of a ordered list of ACE's each one
> >> >> bound to a principal.
> >> >>
> >> >> A user has a set of principals, so to resolve the ACL at any one path
> >> >> for a user the global ACL is filtered to contain only the ACE's with
> >> >> principals that the user has.
> >> >>
> >> >> Computing a final access control bitmap for a user at a location
> >> >> requires ordered processing of all the ACEs relevant to the user at
> >> >> the current path and then all ancestors.
> >> >>
> >> >> The pseudo algorithm to calculate the a grant bitmap and a deny
> bitmap
> >> >> at any level is:
> >> >>
> >> >> function getCurrentLevelBitmaps(currentPath):
> >> >> int grants = 0;
> >> >> int denies = 0;
> >> >> for all ACEs in the ACL at the currentPath:
> >> >> if the user has the principal of the current ACE:
> >> >> int toGrant = 0;
> >> >> int toDeny = 0;
> >> >> if the ACE is a grant:
> >> >> toGrant = the ACE bitmap;
> >> >> else:
> >> >> toDeny = the ACE bitmap;
> >> >> toGrant = toGrant & ~denies;
> >> >> toDeny = toDeny & ~grants;
> >> >> grants = grants | toGrant;
> >> >> denied = denies | toDenies;
> >> >> return (grants, denies);
> >> >>
> >> >
> >> > - Can you please tell me how to calculate the ACE bitmap ?
> >>
> >> That is just the 32bit integer stored in the cassandra column
> >> representing the grant or deny for the principal
> >>
> >> eg
> >> Cassandra rowID : base64(sha1(/content/cassandra/foo/bar ))
> >> Columns: 0_everyone_allow : 0x01, 1_admin_allow : 0x07
> >>
> >> Allows everyone read and admin everything at the path /cassandra
> >>
> >> > - Also I will be more clear if you can provide a sample value for the
> >> input
> >> > and output of this function ? i.e When currentPath=
> >> > /content/cassandra/foo/bar it returns grants=? denies=? some actual
> >> values
> >> > just for my understanding.
> >>
> >> Using the above for a random user (ie has the everyone principal):
> >> grants = 0x01
> >> denies - 0x0
> >>
> >> For the following values
> >> Cassandra rowID : base64(sha1(/content/cassandra/foo/bar ))
> >> Columns: 0_everyone_allow : 0x01, 1_admin_allow : 0x07, 2_ieb_deny :
> 0x01
> >>
> >> results in
> >> dishara : grants = 0x01, denies = 0x00
> >> ieb : grants = 0x00, denies = 0x01
> >> admin: grants = 0x07, denies = 0x00
> >>
> >>
> >>
> >> >
> >> >
> >> >> To combine what is granted at the child level with what is granted at
> >> >> a parent level we need to mask the parent level with the deny at the
> >> >> child level.
> >> >>
> >> >> eg
> >> >> toGrant = grantedAtParent & ~denies;
> >> >> toDeny = deniedAtParent & ~grants;
> >> >> grants = grants | toGrant;
> >> >> denied = denies | toDenies;
> >> >>
> >> >> The simplest way of achieving this is to use recursion again in
> pseudo
> >> >> code:
> >> >>
> >> >> function buildAtLevel():
> >> >> if not root level:
> >> >> (grantedAtParent, deniedAtParent) =
> >> >> buildAtLevel(getParentLevel(currentLevel));
> >> >> (grants, denies) = getCurrentLevelBitmaps(currentLevel);
> >> >> toGrant = grantedAtParent & ~denies;
> >> >> toDeny = deniedAtParent & ~grants;
> >> >> grants = grants | toGrant;
> >> >> denied = denies | toDenies;
> >> >> return (grants, denied);
> >> >>
> >> >>
> >> >> There are some optimisations you can apply here, and there are plenty
> >> >> of opportunities to cache intermediate bitmaps in memory. Just
> caching
> >> >> the ACL reduces resolution to bitwise operations.
> >> >>
> >> >> Principals
> >> >> ----------------
> >> >> Initially keep it simple.
> >> >>
> >> >> read = 0x01
> >> >> write = 0x02
> >> >> delete = 0x04
> >> >>
> >> >> Storage of ACLs.
> >> >> -------------------------
> >> >> I suggest you store ACLs in their own Column Family, where the rowID
> is
> >> >> base64(sha1(path)) or whatever path -> rowid encoding you have
> >> currently.
> >> >>
> >> >> IIRC Cassandra columns come out in the natural order of Strings
> >> >> <order>_<principal>_<allow|deny> and the value is the bitmap of
> >> >> permissions.
> >> >>
> >> >> - If I understand you correctly is
> <order>_<principal>_<allow|deny> is
> >> > one ACE ?
> >>
> >> yes
> >>
> >> If per row there can be a ACL, there should be one additional
> >> > column by default called "ACL" and it will have a comma separated
> string
> >> > which are set of ACEs.
> >>
> >> not necessary as the order of columns is returned in the natural
> >> string sort order (IIRC) so 0_* will be the first followed by 1_
> >>
> >> However, if thats not the case a column called ACL will be required to
> >> list the ACLs in order.
> >>
> >> Correct me if I am wrong.
> >> > - Who stores these ACEs ? any API?
> >>
> >> Not determined yet. It would need an API able to modify ACLs
> >>
> >
> > OK, I am trying to understand. Can you please clarify following.
> >
> > To start with, as I feel I should start storing data to cassandra with an
> > updated column which stores a string which is a comma separated ACE list.
> > i.e when the provider stores a resource at /content/cassandra/foo/bar
> the
> > ACL column can be empty. Does permissions added upon node creation ? Or
> > there is some interface,and when it get called, (path,ACE-list) I will
> > update the row with the new value for the ACL column. If that is the case
> > permission should be granted to a path only of the path exists. OR upon
> > node creation does it suppose to store parent resolved ACE list by
> > default. If that is so it will be more complex for Provider and have to
> > change that to do so.
> >
> >
> >
> >> > - i.e <order> is a auto increment number we have to do a additional
> read
> >> > before storing ACE to check what is the last number for <order>.
> >>
> >>
> >> Ok, that indicates having an ACE column might be better, which would
> >> indicate that no count is required.
> >>
> >> Best Regards
> >> Ian
> >>
> >> >
> >> > Where <order> is 000 to 999 ( I really doubt that a single ACL will
> >> >> have 1000 ACEs ever)
> >> >>
> >> >> Once you have this working, we can wire it into the ResourceProvider
> >> >> or another Sling API.
> >> >>
> >> >> Does that make sense ?
> >> >> Ian
> >> >>
> >> >
> >> >
> >> >
> >> > --
> >> > Thanks
> >> > /Dishara
> >>
> >
> >
> >
> > --
> > Thanks
> > /Dishara
>
--
Thanks
/Dishara