[FOLIO-305] Location-related permissions in auth Created: 08/Sep/16  Updated: 12/Nov/18  Resolved: 03/Nov/16

Status: Closed
Project: FOLIO
Components: None
Affects versions: None
Fix versions: None

Type: New Feature Priority: P2
Reporter: Heikki Levanto Assignee: Heikki Levanto
Resolution: Done Votes: 0
Labels: sprint2
Remaining Estimate: Not Specified
Time Spent: 3 days, 6 hours, 30 minutes
Original estimate: Not Specified

Issue links:
Blocks
blocks FOLIO-326 devise a solution for the authenticat... Open
Sprint:

 Description   

Filip's wireframes introduced a concept of location (circ desk, cataloging), and the idea that the permissions what a user may do depending on the location. Explore how this would change the auth design we have for now.



 Comments   
Comment by Heikki Levanto [ 08/Sep/16 ]

It may be that in the future there will be some other deciding factor instead (or in addition to?) location. Better see if we can make this flexible enough.

Comment by Heikki Levanto [ 09/Sep/16 ]

See also https://discuss.folio.org/t/making-a-distinction-between-patrons-and-system-users-particularly-with-a-perspective-on-permissions/202

Comment by Heikki Levanto [ 09/Sep/16 ]

Taking a look at Filip's wireframe, listing where the location seems to be involved:

  • After login, there is a "Choose Branch" dialog
  • Displayed as a one-character blob on top of the profile icon, the rightmost button on the top bar
  • In the pulldown menu from the same button, there is a place to select a different location

Thinking about other places where locations could be involved:

  • Settings / Users / Staff member permissions has a list of permission sets, where you can define what individual permissions and permission sets are included in a set. No mention of the location. Maybe it should be there, somehow. It does list persons who have this permission set.
Comment by Heikki Levanto [ 09/Sep/16 ]

If the user is allowed to change location just like that, then the location will not offer much additional security. In that case we sould probably view it only as a piece of state in the UI, helping to make some parts more visible when relevant, and less so when not. Maybe also ending up in some audit logs, etc. But I am not (at all) sure how that could be confifgured...

On the other hand, if the location is strictly controlled - like paying fines can only be done at the machine on the fines counter (where the money box is), then it makes more sense wrt security. But again, this needs to be configured somehow, by someone who has the permission to do so...

Comment by Heikki Levanto [ 09/Sep/16 ]

Okapi's permission model only operates with simple string permissions, like "patron-read-sensitive" or "forgive-fine". The auth module will compile all these by going through the permission sets the user has, and recursing into the permission sets contained in those, until all we have is a list of real permissions. This fits well with Filip's permission set thinking. At the moment, when the user logs in, the auth module produces a token that the UI is supposed to pass back at every request. When a request comes to Okapi, it extracts the user from the toke, looks up the permissions given to the user, and creates those permission bits.

I am speculating if we can fake the location-dependent permissions within this model.

Here is one possible way:

  • We extend the user record to contain a set of locations, and additional permissions those locations give.
  • We extend the auth token to include the current location of the user (if any)
  • We extend the code that calculates the full list of permissions to include the permissions for that location
  • We add a service to the auth module to switch location. It takes the current token, and the new location, and produces a new token that contains the location.
Comment by Heikki Levanto [ 09/Sep/16 ]

If we implement this, I suggest we immediately make it not just location, but a set of tags, each working the same way. Location would be one of them, but we could also have some kind of role, position, or even current task.

Of course, the auth service that changes location will have to log it in some kind of audit log.

There is one small drawback for this design: The location-dependent permissions need to be defined individually for each user. But there is a way around this too: If we seed the permission list with the name of a permission set like "location-fine-global", then we can define that set to contain the permissions given to anyone at that location. Of course this set may be empty.

Each user still needs to have a list of permitted locations. Those can come from a template when the user is created, or updated individually or in a batch, using some automation tool (for all users who have location "circ-1" or "circ-2", add also location "circ-3" with the "location-circ-3-global" permission set in it).

Comment by Heikki Levanto [ 12/Sep/16 ]

Oh, a side note: This design is so much compatible with our current way of thinking that we can retrofit it in when necessary. All functional changes will be local to the auth module, Okapi and apps will not notice anything changed. We will need a bit of management functions to set user permissions for different locations, and a function for the user to change location, but everything else will just keep working.

Comment by Kurt Nordstrom [ 28/Sep/16 ]

Thinking this through, I thinking maybe I want to make things a little more generic than "location." How does this look?

The user record currently looks like this:

{ "user_name" : "jack", "tenant" : "diku", "user_permissions" : [ "thing.read", "thing.see_sensitive" ] }

In order to enable flag-based permissions, we can modify the user record to look like the following:

{
"user_name" : "jack",
"tenant" : "diku",
"user_permissions" :

{ "_" : [ "thing.read"], "location.front_desk" : [ "patron.fines", "circulation.all" ] "location.back_office" : [ "patron.all", "circulation.all" ] }

}

In order to request flag-based permissions, we'll add an option "flags" parameter to the permissions request URL.

GET /perms/users/jack/permissions would yield [ "thing.read", "thing.see_sensitive" ]

GET /perms/users/jack/permissions?flag=location.front_desk would yield [ "thing.read", "thing.see_sensitive", "patron.fines", "circulation.all" ]

Permissions flags would just be stored as a field in the user's JWT:

{ "sub" : "jack", "tenant" : "diku", permissions_flags" : [ "location.front_desk" ] … }

When the Authz module is processing a request, it will look at the JWT and check for any permissions_flags defined. If present, it will use them when it requests the permissions for that user from the Permissions module.

In order to change flags (e.g., to a change a user's location), the user would simply need to log in again, and provide a "permissions_flag" parameter. E.g.:

/authn/login?permissions_flag=location.front_desk

Comment by Heikki Levanto [ 29/Sep/16 ]

Looks about right.

Just to be clear, the user may have more than one flag in the JWT, and the permissions call can take a (comma-separated?) list of flags in the parameter. Right?

But I disagree that the user would need to log in again. I think we should have a new call for changing the flags, that the user can issue. It should not require a full logging in, with passwords and all that. It would just take the existing JWT, change the flags as requested, sign it, and return as a new JWT. This comes directly from Filip's UI demo, where there was a button to click to change location.

If we need, we can later make a system where the change-location would need a permission, and use our permission management system to lock users into their flag sets. But that gets hairy pretty soon, and we don't really know what the different installations will need. Better loave that for later.

Comment by Kurt Nordstrom [ 29/Sep/16 ]

Yes, I intended for the flags to permit multiple instances. I should have spelled that out.

I see your point about not requiring a login. We can easily make a "refresh" endpoint to allow a user to request a new token, possibly with new flags enabled.

Comment by Heikki Levanto [ 31/Oct/16 ]

This is not yet implemented, right?

If we make that "refresh" endpoint to change flags in the current token, we could also allow a GET request to retrieve a list of flags and their known values (from the user record), so that the UI can offer a nice way to select the location, or other flags.

Comment by Kurt Nordstrom [ 31/Oct/16 ]

Correct, no implementation has been done at this point.

Which module do we envision serving up the flags?

Comment by Heikki Levanto [ 31/Oct/16 ]

The way I see it, the permissions module keeps a list of various flags and the permissions associated for those, for each user. So it should be the permission module that can also provide the list of allowed flags for the (current) user.

Of course, the service to change the token to include new flags would have to be in the module that can sign new tokens, the one we just renamed to authtoken_module.

Comment by Heikki Levanto [ 01/Nov/16 ]

As far as I can see, Filip's prototype talks about location in two places: Right after logging in it asks the user to choose a location, and in the top-menu, the rightmost button is user info, which includes a pull-down to change location.

I would imagine that we need some supporting functions, like defining what locations we may have in the system, what locations a given user may choose, and what additional permissions any location gives to the user.

Earlier in this issue, we thought that it would make sense not to limit the thing to locations only, but to allow various other flags for things like roles, tasks, or situations. And if we allow the flag to be other than location, it may make sense to allow the user to choose more than one at a time. But that may confuse the UI. Still, since it is so easy to add, it makes sense to allow this on the back end anyway.

I can see two ways how a user may be given the permission to operate on a given location: Either directly, or as a part of a permission set or role (which I see technically the same). I think a permission set is more powerful.

For example, a permission set "music library circulation" would (directly, or indirectly through other sets it includes) grant the user access to "location:music.library.circulation.desk" and if the user has selected that location, access to permissions like "circulate.materialtype.music" or "reservation.location.music.listening.room". (These will again expand into more technical permissions like "reservation.location.write" and ".read")

Filip, what do you think? Have I misunderstood something in your design?

Comment by Heikki Levanto [ 02/Nov/16 ]

Here is my plan how I would implement this:

authtoken_module:

  • Add a new field in the token, like this: ` "flags": [ "location.frontdesk", "location.musiclibrary", "task.newuser.intro" ]`
  • Add a new endpoint to set flags. Returns a new token with the same user and tenant etc, but with new flags. Possibly with params for adding, removing, or replacing tags one at a time.
  • Add a helper method in OkapiToken to extract current flags, and also a new endpoint to return the same

permissions_module:

  • In the routine that calculatesthe full permission set for the user, take an extra parameter that lists the flags the user has (as in "location.frontdesk", and applies those permissions as well as the default ones.
  • Change the permission structure (/perms/permissions) to include not only the regular permissions, but also permissions for each flag, so that each permission set can contain permissions that depend on a flag.
  • No need to change the structures under /perms/users, the users will get permission (sets) that will contain permissions for the various flags.
  • Add a new endpoint somewhere under /perms/users/... to list all the flags that give the user extra permissions. This will be useful in the UI for building a pulldown list where the user chan change location or other flags.

I think this should cover it.

Comment by Heikki Levanto [ 03/Nov/16 ]

Design is complete, implementation will happen in some other issue... Link to this when that time comes.

Generated at Thu Feb 08 23:04:46 UTC 2024 using Jira 1001.0.0-SNAPSHOT#100246-sha1:7a5c50119eb0633d306e14180817ddef5e80c75d.