Help with designing a Role

Given this log message, that I get when opening a custom screen that does a database lookup:

i.j.s.i.h.AccessDeniedExceptionHandler   : resource: roaster_Payment.user.username, type: attribute, action: null

What is wrong with my Role:

@ResourceRole(name = "LunchRole", code = "lunch-role")
public interface LunchRole {

  @EntityAttributePolicy(
      entityClass = Payment.class,
      action = EntityAttributePolicyAction.VIEW,
      attributes = {"user.username"}
  )
  @EntityPolicy(
      entityClass = User.class,
      actions = {EntityPolicyAction.READ})
  @EntityPolicy(
      entityClass = Cost.class,
      actions = {EntityPolicyAction.READ})
  @EntityPolicy(
      entityClass = Payment.class,
      actions = {EntityPolicyAction.READ})
  @EntityPolicy(
      entityClass = Expense.class,
      actions = {EntityPolicyAction.READ, EntityPolicyAction.CREATE})
  @EntityPolicy(
      entityClass = Period.class,
      actions = {EntityPolicyAction.READ, EntityPolicyAction.CREATE})
  @ScreenPolicy(screenIds = "*")
  @MenuPolicy(menuIds = {"i1", "i2", "i3", "i4", "i5"})
  @SpecificPolicy(resources = "ui.loginToUi")
  void appAccess();

  @MenuPolicy(menuIds = "application")
  void menu();
}

Hi,
Could you provide screen XML for your custom screen?

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://jmix.io/schema/ui/window"
        caption="msg://balanceScreen.caption">
    <layout>
        <vbox spacing="true">
            <label value="Your balance is:"/>
            <label id="lblBalance" value="0"/>
            <button id="btnPay" caption="Pay" enable="false"/>
        </vbox>
    </layout>
</window>

controller:

@UiController("roaster_BalanceScreen")
@UiDescriptor("balance-screen.xml")
public class BalanceScreen extends Screen {

  @Autowired private BalanceCalculator calculator;

  @Autowired private CurrentAuthentication currentAuthentication;

  @Autowired private Label<String> lblBalance;

  @Subscribe
  public void onInit(InitEvent event) {
    double balance = calculator.getBalance(currentAuthentication.getUser().getUsername());

    NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.forLanguageTag("nl-NL"));
    lblBalance.setValue(formatter.format(balance));
  }
}

I guess it has to do with the calculator that does a query like:

"select sum(p.amount) from roaster_Payment p where p.user.username = :user"

and :user = username from the currentAuthentication?

Perhaps, the problem relates to DataManager#loadValues, which checks security permissions by entity attributes in a JPQL query.

Try to add the following lines for the resource role:

//allow viewing all attributes of Payment 
@EntityAttributePolicy(
      entityClass = Payment.class,
      action = EntityAttributePolicyAction.VIEW,
      attributes = "*"
  )
//allow viewing all attributes of User entity 
@EntityAttributePolicy(
      entityClass = User.class,
      action = EntityAttributePolicyAction.VIEW,
      attributes = "*"
  )

Yip, works if I add them for all entities I query on. Is that to be expected? i.e. should you add attribute policies for all entitiy policies you already added as readable?

Yes, it’s by design - everything is denied by default.
So normally you should use @EntityPolicy and @EntityAttributePolicy together.

In business logic, you can also use UnconstrainedDataManager instead of DataManager to bypass all data access constraints.