Advice with changed APIs from CUBA-->Jmix that are not covered in the migration "Changed APIs" section

This auto-migration is really not the best it could have been. :frowning:

Right off, I’m unable to compile because the following imports are no longer valid…but not covered in the migration guide…

import com.haulmont.cuba.security.entity.Role;
import com.haulmont.cuba.security.entity.RoleType;
import com.haulmont.cuba.security.entity.UserRole;
import com.haulmont.cuba.security.group.ConstraintPredicate;

A major feature of our application depends on these, so I need to know where the functionality was moved to/etc.

For roles see Resource Roles :: Jmix Documentation

I guess to assign roles, the new RoleAssignmentEntity is now used. (not tried, I’m also still in the migration phase :wink: )

Thank you for the feedback.
We’ve added information about security configuration entities to the migration guide. But perhaps you need to completely reconsider your security configuration, taking into account new abilities like assigning any number of row-level roles to a user, aggregating roles.

What about ConstraintPredicates?

Well, the use case here is in our application, users can define any number of Note Types, and can then specify which users and/or roles can view said Note Types (and thus also any Notes created with these note types). It’s pretty much a requirement for any medical application, at least in the US with our HIPAA laws.

So our Note Type entity contains a list of Users (sec$User in CUBA) and a list of Roles (sec$Role in CUBA) and at login, in a login event listener, we add in ConstraintPredicates that process these lists and control access to the note types/notes.

In fact, the more I look into this, I think all of the functionality used to build out this feature of our application was removed in Jmix. :frowning:

        UserSession session = event.getAuthenticationDetails().getSession();

        ConstraintsContainer newConstraints = AccessConstraintsBuilder.create()
                .join(session.getConstraints())
                .withInMemory(NoteType.class, operationsRUD, isUserAllowedNoteType)
                .withInMemory(PatientNotes.class, operationsRUD, isUserAllowedPatientNote)
                .build();

        session.setConstraints(newConstraints);

Where isUserAllowedNoteType and isUserAllowedPatientNote are ConstraintPredicates.

It seems there is no ConstraintsContainer and thus no AccessConstraintsBuilder and also no ConstraintPredicates in Jmix. As said above, this is a major important feature of our application - and I’m a little shocked that all of this functionality that was used to build it was removed from Jmix!

Am I missing something?

Security subsystem in Jmix was designed from scratch, so it’s really different from CUBA implementation.

If you provide a test project in CUBA that demonstrates your security customizations, we’ll try to suggest you how the same can be done in Jmix. Please make the test project as simple and generic as possible.

Fair enough. I’ll create one and attach it to a post here once done. I appreciate it. I’m not having luck hacking it out in Jmix.

1 Like

Ok @krivopustov - here we go.

This is about as simple as I could make it - just 2 Entities, the AuthenticationEventListener and the 2 ConstraintPredicates.

Just start the app, create a couple test roles, add them to the admin user, create a few test Note Types, play with adding roles to them and such.

All the logic is in the listener and the 2 predicates it uses.

Just to reiterate - this is so that users can create any number of note types, specify which users and/or roles can access these note types - and also, any notes created with the note types. Users also create the roles, and those roles are solely (usually…) for controlling access to notes/types.

helpcuba2jmix.zip (92.5 KB)

(The predicates themselves just process the lists of users/roles added by the user to the note types. IsUserAllowedNoteType sees if the current user is listed in the list of users on the note type, allows if so, then checks the list of roles and if the current user has a role that listed on the note type, allows the note type to be seen. IsUserAllowedPatientNote uses IsUserAllowedNoteType thus if the current user can see the note type on the note, he/she can see the note too. And vice-verse if they can not see the note type.)

OK, thanks. We’ll come back to you in the next few days.

1 Like

Thank you - the help is much appreciated. No point in going on in CUBA and making the eventual conversion even harder.

I have migrated your test project to Jmix and added two options of configuring row-level policies for your case: https://github.com/jmix-projects/row-level-predicates-demo

The first option is a standard declarative row-level role with 2 predicates: NotesRowLevelRole.java. I think it should be enough for most cases. Perhaps you needed some programmatic configuring of predicates in CUBA because you couldn’t assign more than one Access Group to a user. Now in Jmix a user can have
any number of row-level roles.

If you really need some custom logic of assigning roles to a user upon login, look at the second option: DatabaseUserRepository.java. Here you can see how to create and add a new role to a user programmatically.

Please be aware that we a going to change the API of row-level predicates in the next Jmix update because of the problem with serialization(see https://github.com/Haulmont/jmix-security/issues/117). The current API will remain but will be deprecated. I’ll update the project to the newer API when it’s ready.

Regards,
Konstantin

1 Like

Right - we needed multiple “keys” per user, and “Access Groups” in CUBA were a one-per-user thing, so we used roles. The original thread is here: Access Groups: Why only one per user? - CUBA.Platform - though most of the solution was developed with copious help from @stukalov during a long call one weekend over a year ago. :slight_smile:

I’ll take a look at this example; I’m sure it’ll give me what we need!

1 Like

Yeah, that was an amazing online coding session!

1 Like

Ignore previous post; the downloaded example doesn’t work, but it doesn’t matter, I adapted the suggested code into the YouTube video PM example and the code works fine - EXCEPT - in:

                        .map(ResourceRoleEntity::getName)
                        .anyMatch(s -> s.equals(authority.getAuthority()));

::getName needs to be ::getCode (unless code and name are the same in your roles, which for most I think they won’t be).