This is an internal documentation. There is a good chance you’re looking for something else. See Disclaimer.
Widget without ACL / Rule Provider¶
Often times, widgets will experience poor performance because of large queries produces by ACL rules. This mostly happens when dealing with User entities or when long paths are being resolved. To make these widgets faster, we can disable evaluation of ACL rules and implement the required security directly with custom rule providers.
This consists of:
A rule provider class
This grants create, delete, read and write access to entities, as well as reporting and action access.
A rule provider contribution
This defines which entity paths should get granted access to.
Connecting widget config to rule provider
Instructions¶
Follow these steps to enable a rule provider for a widget.
Decide on a rule provider id¶
This can usually just be the widget name, but may need to be more generalized if you want to share rule providers between multiple widgets.
Widget configuration¶
Add a field rule_provider
to the widget configs that should use your rule provider.
Usually, this should not be visible or writable by any user, and instead be set by default value to your rule provider id.
<field name="rule_provider" type="string">
<validations>
<mandatory/>
</validations>
<default type="hard">membership-administration</default>
</field>
Usually, you’ll want to create a changeset that sets this field to your rule provider id on all existing widgets.
Create the rule provider¶
Implement the AbstractEntityRuleProvider
and return your rule provider id from the getId
method.
In the rulesForRequest
, grant access to entities with the use of these methods:
grantCreateAccess
grantEntityReadAccess
grantFullReadAccess
grantEntityWriteAccess
grantEntityWriteAccessForPaths
grantEntityDeleteAccess
For actions and reporting, use grantActionAccess
and grantReportingAccess
.
See Tips for writing rule providers for further information on this step.
Create a rule provider contribution¶
Add a RuleProviderContribution
bean to the configuration class of the module you’re working in.
Then, define which paths should be readable or writable in your rule provider. This can either be done
by hand, with addReadablePaths
and addWritablePaths
, or you can pass in a a form that will be checked for
paths that are needed, with addReadableForms
and addWritableForms
. Additionally, addActionAccess
and
addFullEntityReadAccess
are also available here.
Tips for writing rule providers¶
To make rule providers fast, it is usually helpful to run most or all of it privileged, and to use primary key conditions when granting access. As an example, when wanting to give access to all related registrations of the current user, load all registrations privileged and then create a condition from their keys.
securityManager.privileged().invoke(() ->
principalService.getUserEntity(principal.getName()).ifPresent(user -> {
PrimaryKeyList registrationKeys = queryBuilderFactory.resolveKeys(user, "relRegistration")
.build()
.toPrimaryKeyList();
grantEntityReadAccess(policyBuilder, "Registration", primaryKeyIn(registrationKeys));
})
);
Any non-lookup entity that you grant access to will probably be related in some way either to the current user or the current widget config.
EntityRuleProviderHelperService
offers helper methods to make certain taks easier, like accessing document fields
or granting access based on a constriction.
Remember that this will disable ALL preexisting rules, so we will have to grant access to things that are usually always granted, like the rights of a logged in principal to their own user entity. Also, keep in mind that actions and reports may access paths that are not obviously visible, so test these well.
If any parts of your widget, actions or reports are extensible (that aren’t just forms), you will probably need some way to extend
your rule provider as well. For that, AbstractRuleProviderExtension
may be helpful to you.