Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor user permissions #454

Merged
merged 1 commit into from
Oct 8, 2024
Merged

Refactor user permissions #454

merged 1 commit into from
Oct 8, 2024

Conversation

Mark-Powers
Copy link
Contributor

This fixes a bug where managers could do what they were supposed to. It seems this is caused by having 2 scopes in keycloak: manage and manager-members. We may have differentiated this at one point, but now we do now, there are PIs, managers, and members.

This introduces a class UserPermissions that we can use to set these, rather than having to parse keycloak scopes everywhere we want to use permissions.

This also fixes a small bug in a migration.

Copy link
Contributor

@msherman64 msherman64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with this part of the code, but the changes look sensible to me.

for clarity, it might be better to separate the logic change from the black reformatting, but no big deal 🤷

Comment on lines +50 to +95
class UserPermissions():
manage: bool
manage_membership: bool

def __init__(self, manage, manage_membership):
self.manage = manage
self.manage_membership = manage_membership

@staticmethod
def _get_user_project_role_scopes(keycloak_client, username, project):
role, scopes = keycloak_client.get_user_project_role_scopes(
username, get_charge_code(project)
)
logger.info("SCOPES===")
logger.info(role)
logger.info(scopes)
return role, scopes

@staticmethod
def _parse_scopes(scopes):
# NOTE We have these two scopes defined in KC. In implementation,
# we do not differentiate between them. See our docs for the specifics
# https://chameleoncloud.readthedocs.io/en/latest/user/project.html#user-roles
can_manage = "manage" in scopes or "manage-membership" in scopes
return UserPermissions(
manage=can_manage, # Can edit project metadata/allocations
manage_membership=can_manage, # Can update members
)

@staticmethod
def get_user_permissions(keycloak_client, username, project):
_, scopes = UserPermissions._get_user_project_role_scopes(
keycloak_client, username, project)
return UserPermissions._parse_scopes(scopes)

@staticmethod
def get_manager_projects(keycloak_client, username):
"""Gets project names for all project this user is a manager of
"""
return [
project["groupName"]
for project in keycloak_client.get_user_roles(username)
if UserPermissions._parse_scopes(project["scopes"]).manage
]


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks like it's centralizing the mapping from keycloak scopes -> portal permissions, rather than a bunch of if-then? scattered around?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Now all of the permissions/scope code is here, and a block of code can check against this class for a portal permission. This should prevent bugs with manually parsing/interacting with keycloak scopes each time we check a user's role.

@Mark-Powers Mark-Powers merged commit 4a4ed4a into master Oct 8, 2024
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants