John Turner and I came up with a fairly slick solution to a problem this morning and I thought it was worth sharing.
As you may or may not know, all TI processes, regardless of who actually executes them, run with DataAdmin rights. I confess that I didn't know that, but in my defence I very rarely, if ever, give users the rights to run TI processes.
We had a problem with this because we needed to give the users the ability to run an archiving process but only for those Entities they actually had write access to.
The Entity is passed to the process as a parameter, sure we can limit the options through an Action Button but that wouldn't stop people using Perspectives from typing in anything they liked. Essentially we needed a way to test the element level security within the TI process.
Disclaimer: The only security we needed to worry about is element level security and that's very straightforward, we haven't got the "groups as members of other groups" stuff going on. No Cell Security here either.
So given an Entity we need to find out if the user has WRITE access to it. We tossed around all sorts of options:
- 1. Nested while loops checking for membership of a group and WRITE access for the group for the given entity.
- 2. Building a reference cube with }Client and Entity as the dimensions and populating it with rules.
- 3. Building a reference cube with }Client and Entity as the dimensions and populating it with TI.
The cunning solution we came up with was to use two MDX subsets on the }Groups dimension.
Firstly establish which Groups the user is a member of:
Code: Select all
{FILTER({TM1FILTERBYLEVEL( {TM1SUBSETALL( [}Groups] )}, 0)},
[}ClientGroups].(StrToMember("[}Clients].["+USERNAME+"]"))<>"")}
Code: Select all
{FILTER({TM1FILTERBYLEVEL( {TM1SUBSETALL( [}Groups] )}, 0)},
[}ElementSecurity_Entity].([Entity].['| pEntity |'])="WRITE")}
However, generating an empty subset via MDX causes TI to error, so John had the bright idea of adding in the Admin group. This group is always present and never has any element level security so won't interfere with the results. Now we just need to test for a subset with a size of 1 to know the user has no write access to the given Entity.
Code: Select all
UNION({[}Groups].[Admin]},
{INTERSECT(
{FILTER({TM1FILTERBYLEVEL( {TM1SUBSETALL( [}Groups] )}, 0)},
[}ClientGroups].(StrToMember("[}Clients].["+USERNAME+"]"))<>"")}
,
{FILTER({TM1FILTERBYLEVEL( {TM1SUBSETALL( [}Groups] )}, 0)},
[}ElementSecurity_Entity].([Entity].[' | pEntity | '])="WRITE")}
)})
John took it a stage further and split it into two separate processes, the checking process and the archiving process. Users only have access to the checking process - if security check is passed it calls the archiving process (remember it's running as DataAdmin). In the meantime administrators can use the archiving process without going through the unnecessary security check.
Hope someone finds it useful.