O3: Privileges Plan?

I’ve been hearing questions like this: (These are from reps of 4 different orgs)

  • What kinds of privileges will be possible with OpenMRS3?
  • Has anyone implemented privilege based display/hiding of links/page elements in o3? Something like userHasAccess(a_requiredPrivilege, ?) ?
  • Our customer requires that every single widget needs permissions
  • How does 3.x handle viewing permissions, e.g. only allow limited version of Patient Summary for someone in Lab? eg Putting a **** over certain info? eg if you don’t want a Social Worker to see Diagnosis History, or don’t want an Archivist to see “HIV +”?

Can we talk here about how are folks planning to manage privileges for 3.x?

Back in October 2021, @florianrappl (Mekom) demo’d on a 3.x squad call that he had added a privilege layer to extensions. Mentioned this should work both online and offline:

I’m also wondering: Does this config only hide the information in the UI? Or does it entirely restrict user access to the information? I remember working on a previous system where “hiding” stuff in the UI was not a valid solution, because a knowledgeable user could easily bypass this.



Further context...

What OpenMRS has historically supported:

CCing: @ibacher @mksrom @mksd @jdick @burke @dkayiwa @mseaton @zacbutko @alaboso

Thanks @grace, important conversation here about RBAC in general.

Let us distinguish two areas:

  1. RBAC to features - this is a frontend concern.
  2. RBAC to data - this is a backend concern.

Those points

touch RBAC to features, and as you recalled there is an architecture in place in O3 (with this userHasAccess introduced by @florianrappl :+1:) and we should just learn to leverage it at every corner of the app.

Let’s imagine that we are designing a new appointments widget for the patient chart. When the dev sets up the code for it they should do two things:

  1. Shield it with an O3-privilege, such as maybe userHasAccess("o3.view.appointments.widget", ..).
  2. Liaise with the platform team to ensure that this o3.view.appointments.widget privilege is indeed defined in our backend OpenMRS config for O3.

Cc :warning: @zacbutko and @vasharma05 :point_up:


RBAC to data is a totally different story and is strictly speaking not an O3 question, it’s an OpenMRS question in general. That’s in relation to this point:

How does 3.x handle viewing permissions, e.g. only allow limited version of Patient Summary for someone in Lab? eg Putting a **** over certain info? eg if you don’t want a Social Worker to see Diagnosis History, or don’t want an Archivist to see “HIV +”?

This is a scope creep and cannot be addressed quickly, same goes for location-based access which is also about data.

At @Mekom we have handled RBAC to data through the Data Filter module, that basically adds an RBAC layer for data to Core, until RBAC to data would perhaps one day be fully supported in Core natively.

Note that Data Filter is only about viewing (or not viewing) data.

1 Like

Hi @mksd @grace! AFAIR from the meeting in which this role-based access was introduced, it was only meant to hide the particular widget from the UI, i.e. it wasn’t rendered in the application. I and @zacbutko can have a talk with @florianrappl about how this was implemented in the first place and what are the changes needed in this. Will this be a good step to move ahead?

@mksd is 100% right. There is nothing to do @vasharma05 - a frontend system can never protect somebody from accessing some data. It’s the job of the backend to actually restrict the data access.

The privileges feature of the UI really just does not render (or in most cases) load the relevant widget. Usually, this also prevents the backend call from being made, but independent of that the backend call should never succeed (or not be relevant w.r.t. the given privileges).

TL;DR: Actual protection can only be done via the backend - the frontend’s job is to be optimized and only show to the user what the user can access.

3 Likes

Totally got your point @florianrappl! Thanks alot!

There’s nothing to do in the sense that the ESM framework has a mechanism for handling this display hiding. However, there are, however, at least three things that need to be done in this area:

  1. We need to ensure that privilege checks are correctly added to frontend apps where appropriate. Currently only three places in the frontend use this utility: the implementer tools, the attachments view, and the RefApp links in the home page app. (OHRI apps also do not seem to leverage this functionality).
  2. At a framework level, an implementer should be able to configure the privileges needed to access an extension via the configuration schema.
  3. We’ve traditionally had separate permissions to grant users access to view data even if they don’t have access to modify the data. In general, it would be good if we had slightly more fine-grained permissions at the app level so that, e.g., the extension renders as long as the user has the “view” permission, but any actions only render if the user has the “add / edit / delete” or “manage” permission. Right now, only the attachments part seems to implement this model.

Of course, the backend will still block users without appropriate permissions from submitting data but it’s a little weird that the user can bring up a screen and fill it all in only to have the request rejected.

1 Like

Thanks for bringing this up, @grace. OpenMRS frontend and backend would benefit greatly from a thoughtful approach to privileging. We started with privileges & roles, where privileges controlled access to specific API methods and roles allowed the privileges to be grouped for easier assignment/management. This worked well initially, but ran into a some problems that we’re likely to exacerbate or recreate on the frontend if we’re not careful:

  1. As the number of privileges grow, they become difficult for admins to manage. Roles can help assign groups of privileges, but admins can’t easily know which privileges are needed for a workflow. This led OpenMRS 2.x to a hacky approach of granting all backend privileges to users and managing feature-level privileges in the frontend, which isn’t a viable approach for OpenMRS 3.
    • If frontend features aren’t behaving as expected for a user because of a privileging issue, how does an admin troubleshoot the problem?
    • Can we come up with a way of more effectively communicating/documenting the set of privileges needed or used by a module/widget. In the past, we considered the idea of “privilege groups” as a way to define a collection of privileges needed for a feature/module, but this never got implemented.
  2. Roles (groups of privileges) are often misinterpreted or created as organizational roles (“Doctor” or “Nurse”) when they are really intended to be application roles (e.g., “Can write orders” or “Can view nursing dashboard”) – i.e., application roles should focus on what a user can do with the application and not their job title.
    • The UserGroup feature could help us in separating organizational roles from application roles.
1 Like

For me I understand that customizability is important, but would hesitate to say that deciding widget permissions should be left to implementors. I think security of data is one area where we should be prescriptive as a platform. That is, we should put a lot of thought into what the permissions are and what they mean, and a widget should know where it fits in that data privacy / security paradigm. Totally agree with @florianrappl that this is only part of the solution, and backend also needs to agree to this permission schema together. However, if both parts are moving it can be hard to know what is actually happening and what is secure / private.

I think the solution for customizing the implementation then comes from assigning permissions to roles. Once we have.a stable idea of what permission does what, we can set it up so that my Nurse has different permissions than her Nurse. This way customizability and security can both win.

To @burke 's point, we should have good transparency in minimally docstrings and optionally docs or UI that shows clearly the permissions that each workflow depends on. Access issues should give clear alerts as to what permission is missing.

To @burke 's other point, I can see how permission groups could be useful

1 Like

Adding more to the history, we also created this module: Privilege Helper Module - Documentation - OpenMRS Wiki :slight_smile:

1 Like

Follow-up discussion here: Privileges and Access Controls/RBAC in OpenMRS 3.x

Resurrecting this one @mksd @grace

We need to more or less do the above for the dispensing app (set UI privileges around it).

A few questions:

  • Have we come up with a naming convention for privileges? (Perhaps “o3.[esm-name].[suffix]”, so ie “o3.dispensing-app.dispense.create”)

  • Have we come up for a way for an ESM to define which privileges it uses? Not sure “liaise with the platform team” is a long-term solution, and I don’t think we want all privileges that ESM use defined in the platform? (or maybe that’s okay?) At minimum, for a start, we could just document in an ESM’s README the privileges that you need to have defined for that ESM to work?

  • Searching through the patient chart and and patient management codebases, I’m only finding a few usages of “userHasAccess” tag… so it looks like we haven’t applied many UI-level privileging in O3 (yet)?

fyi @ibacher @pirupius @mseaton

Thank all!

Take care, Mark

Yep, that’s basically right.

In general, I don’t know that we need or want a lot of O3-specific privileges. For the most part, the ESM’s should just be relying on the privileges necessary for the APIs they call. Implementation-specific privilege configuration is already supported by the config system, meaning that an implementation can layer whatever arbitrary privileges they would like on top of ESMs at run-time.

Extensions can define privileges they need when they are registered via the privileges property (see here) which internally gets converted into a userHasAccess() call. In general, it’s probably best for extensions to rely on declared privileges rather than explicit userHasAccess() calls (or the UserHasAccess component).

Thanks for quick response @ibacher !

ie, do you mean by Iniz, or is there some other way the config system allows defining privileges?

In O2 we specifically broke up API-level privileges from App-level privileges (which we prefix with “App:” or “Task”). We generally give the most users all API-level privileges, and then control access via App-level privileges. Not super-great from a security perspective, but we were running into a lot of cases where it was hard to control what privileges were needed for what functionality. For instance, we could give a Reporting user an API-level “View Reports” privilege, but then that report would mysteriously fail because they didn’t have an API-level “View Patients” privileges… because we didn’t want the Reporting user to be able pull up the patient dashboard, but the “View Reports” page would call a “View Patients” API method (not sure if that an actual example of a problem we ran into, but for examples sake…)

Also, there are not always app-level privileges that map directly to API privileges… for instance, in the requirements for the dispensing app, create, edit and delete map pretty well to API privileges, but there are some more finer-grained ones requested that can’t really be defined at the API level. See the “Modify…” privileges in the ticket below, as well as the need for a “delete-only-if-they-created it” (the latter I guess we could implement at the API level).

https://issues.openmrs.org/browse/O3-1709

Take care, Mark

I meant that in the frontend configuration you can use the feature in this PR. That doesn’t define new privileges (for that, we can use Iniz or the config.xml as appropriate).

I get that… I suppose if we need these kind of app-level privileges it makes sense to come up with a convention. It’s not something we’ve currently implemented in O3, though.

@grace last-minute, but if we do have time, it would make sense to discuss on the TAC tomorrow if the right people are in attendance?

also fyi @mseaton see the posts from the last few weeks for the discussion to-date.

Take care, Mark

Sorry Mark the agenda will be pretty packed as-is with the Form Engine planning. Can we make this the topic for next week? Is that okay with you? I’ll be OOTO but I hope @dkayiwa will take lead on the TAC call again next week.

Fair enough… let’s pencil it in for next week, though hopefully we might be able to resolve it asynchronously before then…

So a general consensus was reached to use the OpenMRS 2.0 “Task:”-prefixed privileges to refer to “application-level” privileges within the Dispensing App.

You can see the current PR here:

If we do come up with a preferred naming pattern/convention for O3 privileges, we can likely migrate what we do in the Dispensing App.

@mogoodrich just to confirm, should i take it that this was resolved? Or do you still need it on tomorrow’s TAC agenda?

Thanks @dkayiwa ! I moved forward with the consensus above, so as along as there are no disagreements with that, we don’t need to discuss.