Permission for Functions Called within a Function?


We have a function on a type that the user needs to use. For example, SomeType.someFunction(). The users are granted access to this in their role via allow:SomeType:someFunction:.

However, this function calls SomeType.removeAll(filter) within it. The user receives a 403 error (upon calling the API SomeType?action=someFunction) that they are not authorized to access Target [tenant/tag/SomeType?action=removeAll], even though they are not directly calling that.

The user does not, and should not, have access to SomeType.removeAll; the function they are using, someFunction, does checks to make sure the filter includes only things that the user should be removing.

How to we make sure that the user is able to run SomeType.someFunction without granting them SomeType.removeAll?



User need to have permissions to call SomeType.removeAll, if you don’t want to grant him this then encapsulated the logic in a batch or map-reduce job that will call your removeAll.



@bachr Here is what the documentation specifies:

Action Access (Permission) evaluation
* Permissions can grant or deny access to the given resource.
* Actions that will be evaluated for access:
    * Root actions without @action(authz=‘never’) annotation – vast majority of actions
    * Child actions with @action(authz=‘always’) annotation

This would mean that because removeAll is a child action in this instance it should be allowed unless it has @action(authz=‘always’) which it does not.

1 Like


To expand with more information. The parent method is called ItemToIndex.updateMappings which can potentially call ItemtoIndex.removeAll based on the input.

Here are some of the authorization information.

Authorizer.actionAuthzRoles("ItemToIndex", "updateMappings").join(', ');
"SystemAdminRole, DeveloperRole, 3MInternalReadRole, VadAdminRole"

Authorizer.actionAuthzRoles("ItemToIndex", "removeAll").join(', ')
"SystemAdminRole, DataIntegratorRole, TenantCreatorRole, DeveloperRole, VadAdminRole"

Authorizer.actionAuthorization("ItemToIndex", "updateMappings", '').accessInfo
"ALLOWED - ItemToIndex.updateMappings after evaluating all access objects"

Authorizer.actionAuthorization("ItemToIndex", "removeAll", '').accessInfo
"DENIED - ItemToIndex.removeAll after evaluating all access objects"

These permissions are expected and desired. We don’t want that specific user with the 3MInternalReadRole to be able to run removeAll directly but only through a specific function updateMappings.



The issue is that ItemToIndex.removeAll() has a securityLevel. In 7.8 (looser than 7.9), the action authorization for child action will is enforced if the parent action has the @authz=(authzChildActions=true) annotation, or if the child action has the @authz(authorize='always') annotation or if the action has a security level. The latter was documented in the 7.8 release notes topic of the documentation that I see is missing in As you can see from the screenshot, ItemToIndex.removeAll() doesn’t have a security level so you could invoke ItemToIndex.remove() on each object you want to remove.




Where does the security level come from and how can it be changed?

According to the type documentation, it comes from finding the max value (min security level) among all the roles which have this permission, but if I do an allRoles call to the permission as you made it above, it is empty.

To further complicate things, running that same statement you have above in our QA environment returns null instead of 2. An allRoles call there also gives an empty array.
Why would the same permission, from the same provisioned package, have two different security levels in the different environments, when, as far as I can tell, nothing is setting it. (Prod gives a repositoryVersion('base') of 7.8.23, QA gives 7.8.68)



SecurityLevel is defined in code for Platform Roles. Cannot be changed … basically actions ‘protected’ by those Roles will have a security level and will be evaluated for access in 7.8. In 7.8 they could be explicitly assigned to another Role, but in 7.9 they will not be able to be assigned. SecurityLevel for the action above should be the same in both cases.



A summary for people who may be interested…

The removeAll function has a securityLevel assigned to it in the specific version that we currently have in production. This means just granting access to the parent function that calls it will not work.

More recent versions do not assign a securityLevel to removeAll, and I am told it will not have a securityLevel assigned to it 7.9, so in those version the original scenario should work fine.

Since we do not know when production will be upgraded to a new version, the current solution is to change from removeAll to use fetch and then remove on each returned instance, sinceremove does not have a securityLevel assigned.

1 Like