Bug in Transfer Stock / Adjust stock

Hi All,

I was trying to transfer or adjust a stock as Manager of the location by this menu:

image

However if I try this i get this error:

Isn’t it for a Manager not possible to edit stock with this way?

Isn’t it for a Manager not possible to edit stock with this way?

I honestly don’t know why we made that decision, but it was done explicitly as evidenced by the commit

In the most recent version 0.8.20 (to be released next week) we made a small change to allow a system administrator to assign access rule overrides for any action in the system through the runtime configuration file (openboxes-config.groovy).

That setting would look like this for you.

openboxes.security.rbac.rules = [
        [controller: 'inventoryItem', actions: ['adjustStock', 'transferStock'], accessRules: [minimumRequiredRole: org.pih.warehouse.core.RoleType.ROLE_MANAGER]]
]

This is actually probably present in the 0.8.19 as well, but we haven’t officially published that release yet either.

I’ll probably publish both releases to GitHub (and their associated release notes here) by the middle of next week. If you’re itching to get this fixed ASAP check in with me early next week and I’ll send you a link to one our recent nightly builds.

I’ll wait till you release it on Github, thnx!

Hello Justin,

Can you confirm this option is available in Release 0.8.20? Didn’t saw it in the release description.

It was added in 0.8.19 with the following ticket

OBPIH-4169 Added role-based access control rules for controller actions that relate to data removal

Bump!, So I have now the latest version. Is there a list of controllers / actions for the ''openboxes.security.rbac.rules"?

I used this:

openboxes.security.rbac.rules = [
        [controller: '*', actions: ['delete'], accessRules: [ minimumRequiredRole: RoleType.ROLE_SUPERUSER ]],
        [controller: '*', actions: ['remove'], accessRules: [ minimumRequiredRole: RoleType.ROLE_SUPERUSER ]],
        [controller: '*', actions: ['removeItem'],  accessRules: [ minimumRequiredRole: RoleType.ROLE_MANAGER ]],
        // We probably need a way to handle wildcard in actions as well
        //[controller: '*', actions: ['remove*'], access: [RoleType.ROLE_SUPERUSER]],
        //[controller: '*', actions: ['delete*'], access: [RoleType.ROLE_SUPERUSER]]
        // ... otherwise we'll need to include explicit rules for everything
        [controller: 'order', actions: ['remove'], accessRules: [ minimumRequiredRole: RoleType.ROLE_ASSISTANT ]],
        [controller: 'order', actions: ['removeOrderItem'], accessRules: [ minimumRequiredRole: RoleType.ROLE_MANAGER ]],
        [controller: 'order', actions: ['deleteDocument'], accessRules: [ minimumRequiredRole: RoleType.ROLE_ADMIN ]],
        [controller: 'invoice', actions: ['eraseInvoice'], accessRules: [ minimumRequiredRole: RoleType.ROLE_MANAGER ]],
        [controller: 'invoiceApi', actions: ['removeItem'],  accessRules: [  minimumRequiredRole: RoleType.ROLE_MANAGER, supplementalRoles: [RoleType.ROLE_INVOICE] ]],
        [controller: 'stockTransfer', actions: ['eraseStockTransfer'],  accessRules: [ minimumRequiredRole: RoleType.ROLE_MANAGER ]],
        [controller: 'stockMovementItemApi', actions: ['eraseItem'],  accessRules: [ minimumRequiredRole: RoleType.ROLE_ASSISTANT ]],
        [controller: 'stockMovement', actions: ['remove'], accessRules: [ minimumRequiredRole: RoleType.ROLE_ASSISTANT ]],
        [controller: 'stockRequest', actions: ['remove'], accessRules: [minimumRequiredRole: RoleType.ROLE_ASSISTANT]],
        [controller: 'glAccount', actions: ['delete'], accessRules: [minimumRequiredRole: RoleType.ROLE_SUPERUSER]],
        [controller: 'glAccountType', actions: ['delete'], accessRules: [minimumRequiredRole: RoleType.ROLE_SUPERUSER]],
        [controller: 'preferenceType', actions: ['delete'], accessRules: [minimumRequiredRole: RoleType.ROLE_SUPERUSER]],
        [controller: 'purchaseOrderApi', actions: ['delete'], accessRules: [ minimumRequiredRole: RoleType.ROLE_ASSISTANT]],
        [controller: 'purchaseOrderApi', actions: ['rollback'], accessRules: [ supplementalRoles: [RoleType.ROLE_APPROVER]]],
        [controller: 'stockTransferApi', actions: ['delete'], accessRules: [ minimumRequiredRole: RoleType.ROLE_MANAGER]],
        [controller: 'stockMovementApi', actions: ['delete'], accessRules: [ minimumRequiredRole: RoleType.ROLE_ASSISTANT]],
        [controller: 'product', actions: ['merge'], accessRules: [ minimumRequiredRole: RoleType.ROLE_ADMIN]],
        // Other controller actions that might need explicit rules
        //[controller: 'putawayItemApi', actions: ['removingItem'], access: [RoleType.ROLE_MANAGER]],
]

But still same error… Anyway I want to finetune it but can’t figure out which controller.

We actually needed to make an additional change in 0.8.22-hotfix1 to get this working properly.

We haven’t officially published this release yet but plan to do so in the next day or two.

For now, you can download the latest release build here.
https://bamboo-ci.pih-emr.org/browse/OPENBOXES-SDNAV-80/artifact

Once you’ve upgraded the WAR file, the role-based access control rules configuration should look like this. And you just need to include permissions that you intend to override.

openboxes.security.rbac.rules = [
    [controller: 'inventoryItem', actions: ['adjustStock', 'transferStock'], accessRules: [minimumRequiredRole: org.pih.warehouse.core.RoleType.ROLE_MANAGER]]
]

And make sure the minimumRequiredRole includes the fully qualified class name (including the package)

minimumRequiredRole: org.pih.warehouse.core.RoleType.ROLE_MANAGER

or you import the RoleType class at the top of the file.

import org.pih.warehouse.core.RoleType

And lastly, make sure this gets added to openboxes-config.groovy (not openboxes-config.properties).

Thanks,

Do you have a list of all options (controllers) you can set/override with this?

Unfortunately, no. At least not without writing some code.

More recent versions of Grails have a feature where you can generate a report of all URL mappings.

For now, your best bet is to consult the UrlMappings configuration.

The general rule is pretty basic so just look through controller code to see what actions are available.

"/$controller/$action?/$id?" {
    constraints {
        // apply constraints here
    }
}

If you really wanted to get a definitive list of the controller actions available, the following code (executed in the Console) would do the trick.

grailsApplication.controllerClasses.each { controller ->
  controller.uris.each { uri ->
    println "${uri}"
  }
}

Personally, I wouldn’t go through the trouble because you can determine the proper URI using browser dev tools or by asking us for our thoughts.

Ah yes working now.

However, in the Groovy file it states: minimumRequiredRole

Is there an option for RequiredRole? So no minimum but that you must have a role…

Ok, one last error.

If I want to filter out settings that only Admins may do I add this:

[controller: 'admin', actions: ['cache'], accessRules: [minimumRequiredRole: org.pih.warehouse.core.RoleType.ROLE_ADMIN]]

But then I get this error:

 2023-06-07 11:57:17,567 [Timer-0] ERROR reloadconfig.ReloadConfigService  - Failed parsing and merging config file /opt/tomcat/.grails/openboxes-config.groovy changes
 org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
 script1686131837543530510995.groovy: 29: No map entry allowed at this place
 . At [29:12]  @ line 29, column 12.
    [controller: 'admin', actions: ['cache'], accessRules: [minimumRequiredRole: org.pih.warehouse.core.RoleType.ROLE_SUPERUSER]],
               ^
 
 1 error
 
 	at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:302)
 	at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:969)
 	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:519)
 	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:497)
 	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:474)
 	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:306)
 	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:287)
 	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:267)
 	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:214)
 	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:224)
 	at groovy.lang.GroovyClassLoader$parseClass.call(Unknown Source)
 	at groovy.util.ConfigSlurper.parse(ConfigSlurper.groovy:120)
 	at groovy.util.ConfigSlurper$parse$3.call(Unknown Source)
 	at grails.plugins.reloadconfig.ReloadConfigService$_checkNow_closure2.doCall(ReloadConfigService.groovy:56)
 	at sun.reflect.GeneratedMethodAccessor436.invoke(Unknown Source)
 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 	at java.lang.reflect.Method.invoke(Method.java:607)
 	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
 	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
 	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
 	at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1070)
 	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)
 	at groovy.lang.Closure.call(Closure.java:282)
 	at groovy.lang.Closure.call(Closure.java:295)
 	at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1220)
 	at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1196)
 	at org.codehaus.groovy.runtime.dgm$110.invoke(Unknown Source)
 	at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:270)
 	at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
 	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
 	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callSafe(AbstractCallSite.java:90)
 	at grails.plugins.reloadconfig.ReloadConfigService.checkNow(ReloadConfigService.groovy:39)
 	at grails.plugins.reloadconfig.ReloadConfigService$checkNow.call(Unknown Source)
 	at grails.plugins.reloadconfig.ReloadConfigUtility$_configureWatcher_closure1.doCall(ReloadConfigUtility.groovy:37)
 	at sun.reflect.GeneratedMethodAccessor923.invoke(Unknown Source)
 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 	at java.lang.reflect.Method.invoke(Method.java:607)
 	at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
 	at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
 	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
 	at grails.plugins.reloadconfig.ReloadConfigUtility$_configureWatcher_closure1.doCall(ReloadConfigUtility.groovy)
 	at sun.reflect.GeneratedMethodAccessor922.invoke(Unknown Source)
 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 	at java.lang.reflect.Method.invoke(Method.java:607)
 	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
 	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
 	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
 	at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1070)
 	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)
 	at groovy.lang.Closure.call(Closure.java:282)
 	at groovy.lang.Closure.call(Closure.java:277)
 	at groovy.lang.Closure$call.call(Unknown Source)
 	at TimerTask_groovyProxy.run(Script1.groovy:7)
 	at java.util.TimerThread.mainLoop(Timer.java:555)
 	at java.util.TimerThread.run(Timer.java:505)

Authorization is based off a hierarchy of roles.

Superuser > Admin > Manager > Assistant > Browser

The only role that behaves the way you suggested is Superuser since there’s no role above it.

We could potentially add support for a requiredRole, but it’s going to be awhile before that makes it into a release since we’re in a code freeze while we upgrade to Grails 3+.

Justin

Can you show the entire RBAC rules configuration in openboxes-config.groovy? It seems you may have added this rule outside of that configuration property.

If I want to filter out settings that only Admins may do I add this:

By the way, I believe you can do something like this (using a wildcard in the actions)

[controller: 'admin', actions: ['*'], accessRules: [minimumRequiredRole: org.pih.warehouse.core.RoleType.ROLE_ADMIN]]