Permission Helpers
Jim Pease
I am a little confused as to what I am supposed to pass in the 'targetRef' param to the permissions helper. Based on the configuration of my tool, I am passing a site reference, in some cases, and in others I am passing a reference which is also the id for a realm. My service parses this reference and will return the reference in the authzgroup collection (returned by getEntityAuthzGroups).
Everything seems to work as expected, but I am getting the following warning in my logs:
WARN: Sql.dbRead: sql: select DISTINCT FUNCTION_NAME from SAKAI_REALM_FUNCTION SRF inner join SAKAI_REALM_RL_FN SRRF on SRF.FUNCTION_KEY = SRRF.FUNCTION_KEY inner join SAKAI_REALM_ROLE SRR on SRRF.ROLE_KEY = SRR.ROLE_KEY inner join SAKAI_REALM SR on SRRF.REALM_KEY = SR.REALM_KEY where SRR.ROLE_NAME = ? and SR.REALM_ID in maintain (2006-07-17 10:56:27,644 http-8444- Processor24_org.sakaiproject.db.impl.BasicSqlService)
java.sql.SQLException: Statement parameter 2 not set.
It turns out that the buildHelperContext method in the PermissionsAction class is removing this realm from the realms collection (line 212), thus resulting in an empty collection being passed to the getAllowedFunctions method in the AuthzGroupService.
Am I incorrectly using the helper, or is this a logging issue?
Glenn Golden
The permissions helper edits the permissions associated with a particular specific entity in Sakai. Permissions on an entity are stored by the AuthzGroup service in AuthzGroups.
The way an AuthzGroup is associated with an entity is:
the entity REFERENCE is used as the AuthzGroup ID.
So, for example, for a site id="XYZ", the AuthzGroup ID is:
/site/XYZ.
For content in that site's top level folder called "test.txt", the AuthzGruop ID is:
/content/group/XYZ/test.txt
The permissions helper needs to know which AuthzGroup to edit, among other things.
The way the permissions helper, or any helper, gets information is from the ToolSession of the tool invoking the helper. Get this object:
ToolSession toolSession = SessionManager.getCurrentToolSession();
You can call setAttribute() on your toolSession, using the names defined in the helper tool's "API". For the permissions helper, see the file:
org.sakaiproject.authz.api.PermissionsHelper
TARGET_REF is defined:
/** Set this tool session attribute to the entity reference of the entity whose AuthzGroup is to be edited. */
static final String TARGET_REF = "sakaiproject.permissions.targetRef";
So you need to choose what entity you are setting permissions on. Unless you are a site editor, it is not likely you want to include a site reference (unless you are doing the big cheat and not defining your own entities, but instead doing security with a big shortcut on the site related to your tool's context. Works, for now, somewhat fragile, but the big problem is it is not doing fine grained entity security - no way to treat each of your context entities separately).
The best example is that of the resources tool doing "folder permissions" on a folder in context XYZ called "folder2". The reference to this folder, and thus the AuthzGroup group id, is:
/content/group/XYZ/folder2/
And that's what you pass in as TARGET_REF.
- * *
The removal code you refer to is where the permissions tool is computing the permissions that are ALREADY SET on this entity at a HIGHER LEVEL, such as in ContentHosting at a containing folder. It looks at all the AuthzGroups for the entity, minus the one that is specific to the entity for this. These are shown in the editor, but the user cannot change them.
Permissions in Sakai are accumulated over the entire set of AuthzGroups selected for each entity. Each "EntityProducer" application that supports entities, references, and permissions, defines what this set is for each entity. For example, in ContentHosting, for a file in context XYZ in folders "top" and "middle", whose reference is:
/content/group/XYZ/top/middle/target.txt
the set of AuthzGroups are:
/content/group/
/content/group/XYZ/
/content/group/XYZ/top/
/content/group/XYZ/top/middle/
/content/group/XYZ/top/middle/target.txt
/site/XYZ
The allows security definitions defined for any of the folders or the site, or the specific file, to be used.
Anything defined "above" the file cannot be changed by the file's definitions, since this is all accumulative (i.e. we give permissions at any level, but we cannot take them away).
So the code you see is computing what's fixed. What is edited, though, is the TARGET_REF AuthzGroup.
- * *
There's one interesting case where you send in another reference to the PermissionsHelper. This is when the AuthzGroup that defines which roles to show in the helper (which shows a role by permission matrix for editing) is not in the TARGET_REF. For ContentHosting, there is probably not even an AuthzGroup defined for a particular file. In this case, the roles are defined by the related Site reference. So we pass in:
/site/XYZ
as the ROLES_REF attribute.
- * *
It may be that we have a bug in the code for cases where there is only ONE AuthzGroup in the set for an entity. This must be a very rare occurrence... and is probably indicating an error in the code that computes the AuthzGroup set for the entity. But it is also probably something we should deal with better... a JIRA would be good here.
Contact me about your AuthzGroup set you are computing for your entities... maybe there's something not quite right there.
Further responses from Glenn Golden to Jim Pease
> Just to clarify your statement:
>
> > Anything defined "above" the file cannot be changed by the file's
> > definitions, since this is all accumulative (i.e. we give permissions
> > at any level, but we cannot take them away).
>
> Based on your example below, if I am in a role with permission to do something in AuthzGroup "/content/group/", then it doesn't matter what is set at "/content/group/XYZ/" or below?
correct.
>
> Regarding the AuthzGroup set I was trying to use...
>
> Given a reference like "/gmt/global", I would return that reference in the AuthzGroup collection, whereas given a reference like "/gmt/ XYZ" where "XYZ" is a context id, I would call addSiteContextAuthzGroup.
>
good
> Essentially, based on a global configuration of my tool, I would pass a targetRef like "/gmt/global", otherwise I would use a context specific reference like "/gmt/XYZ". The idea was that in certain cases (when dealing with "global" things) permissions would be checked against the global realm regardless of the context. Am I stepping out of the bounds of the expected use here?
>
sounds good
> Also, I've noticed in most cases that the fallback is on the site context using addSiteContextAuthzGroup. Although I mention using this above, shouldn't I be using my own context specific AuthzGroup? For example, given a reference "/gmt/XYZ", my AuthzGroup set would contain "/gmt/XYZ" instead of "/site/XYZ", since the site reference implied by that authzgroup id doesn't belong to me?
>
It is ok to include the "/site/..." AuthzGroup. Common practice is to manage permissions at the site level for all related entities.
So it appears that your only problem is that you sometimes (the global case) end up with a single AuthzGroup in the set, and the permissions helper is assuming, incorrectly, for it's "above" check, that there will be more. We can fix that.