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

Feature/workspace user management #4337

Open
wants to merge 52 commits into
base: main
Choose a base branch
from

Conversation

fortunkam
Copy link

@fortunkam fortunkam commented Feb 7, 2025

Resolves #4169 "Enable Workspace Owners to add multiple users and assign WorkspaceResearcher role"

This pull request introduces a new user management feature to the api_app project, along with several related changes. The key changes include the addition of new routes for managing workspace users, updates to the configuration to enable user management, and the creation of new schemas and models to support user roles and assignments.

The User management feature will only be visible if the user is a TreAdmin, the USER_MANAGEMENT_ENABLED flag is enabled and the Workspace has Entra ID/AAD groups enabled.

User Management Feature:

  • api_app/api/routes/api.py: Added workspace_users to the list of routes and included conditional routing based on the USER_MANAGEMENT_ENABLED configuration. [1] [2]
  • api_app/api/routes/workspace_users.py: Introduced new routes for getting workspace users, assignable users, workspace roles, assigning users to roles, and removing user assignments.

Configuration Updates:

  • api_app/core/config.py: Added a new configuration variable USER_MANAGEMENT_ENABLED to toggle user management features.

Schema and Model Additions:

Other Changes:

Version Update:

@github-actions github-actions bot added the external PR from an external contributor label Feb 7, 2025
Copy link

github-actions bot commented Feb 7, 2025

Unit Test Results

617 tests   617 ✅  7s ⏱️
  1 suites    0 💤
  1 files      0 ❌

Results for commit 2ce6937.

♻️ This comment has been updated with latest results.

Copy link
Member

@marrobi marrobi left a comment

Choose a reason for hiding this comment

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

Great to see this, couple of comments, will likely give it a go and review further next week. Thanks!

sp_graph_data = self._get_app_sp_graph_data(workspace.properties["client_id"])
app_id_to_role_name = {app_role["id"]: app_role["value"] for app_role in sp_graph_data["value"][0]["appRoles"]}

for group in (item for item in roles_graph_data["value"] if item["principalType"] == PrincipalType.Group.value):
Copy link
Member

Choose a reason for hiding this comment

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

Is this not just going to add the user to a random group that has been assigned to the app role?

Copy link
Member

Choose a reason for hiding this comment

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

the terraform uses:

resource "azuread_group" "workspace_owners" {
  count            = var.create_aad_groups ? 1 : 0
  display_name     = "${var.workspace_resource_name_suffix} Workspace Owners"
  owners           = [var.workspace_owner_object_id]
  security_enabled = true
}

We should maybe output and store the group IDs as workspace properties? If that property exists we add to the group, if it doesn't we add direct to the app role?

Copy link
Author

Choose a reason for hiding this comment

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

Interesting, I think when we created this originally we made an assumption that there would only be one group assigned to the app role (for each role type) since that is what the "Add groups" option did. We can make that more explicit.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, we need to, who knows what group might get added to the app role, and then unknowingly other people get added to it and end up with access to something they shouldn't.

Copy link
Author

Choose a reason for hiding this comment

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

Do we need to store this in the Cosmos config somewhere or can we just infer the names from convention?

Copy link
Member

Choose a reason for hiding this comment

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

I think we need to add the group IDs in outputs.tf for the workspace, and porter.yaml, then the IDs will be stored in cosmos. I think check for existence of that value - will need to be conditional on groups being enabled - and if is there use the ID of the group.

That make sense?

Copy link
Author

Choose a reason for hiding this comment

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

Looks like there are already some properties being exported I might be able to use create_aad_groups and can then lookup based on the name and the app_role_id_* properties.

Copy link
Author

Choose a reason for hiding this comment

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

Have added an implementation of this, let me know what you think.

group_name = group_details[0]
workspace_app_role_field = group_details[1]

for group in [item for item in roles_graph_data["value"] if item["principalType"] == PrincipalType.Group.value]:
Copy link
Member

Choose a reason for hiding this comment

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

Bit confused, might need to talk through it. How does roles_graph_data["value"] contain groups? looks to be getting existing user role assignments?

Copy link
Author

Choose a reason for hiding this comment

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

roles_graph_data contains a list of appRoles assigned to the API, it is a mixture of users and groups

Copy link
Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Ah, got it, then look through those groups by name?

If it works, ok, think using the workspace outputs would be more straightforward.

<Stack tokens={{ childrenGap: 20 }} styles={{ root: { paddingTop: 20 } }}>
<Stack tokens={{ childrenGap: 10 }} verticalAlign="center">
<Label>User</Label>
<TextField
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to have a picker here of some sort, I tried with an email in the tenant and got a 500 back. Didn't dig any deeper.

Copy link
Author

Choose a reason for hiding this comment

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

Originally I had a picker here but it didn't look great with large numbers in the tenant. Ideally what it needs is some sort of search functionality. For external users to a tenant it needs to be added as the user principal name rather than the email address so it is a bit clunky. (e.g. myemail_microsoft.com#EXT#@MyTenant.onmicrosoft.com).

I can readd the name picker as a short term measure and investigate the search functionality as a longer term solution (possibly a new issue)?

Copy link
Member

Choose a reason for hiding this comment

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

Not sure what the picker looks like... got a snip?

Yes, agree, search would work better.

Copy link
Author

Choose a reason for hiding this comment

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

image

This was the initial attempt, for each user we show the Display Name and the User Principal Name (email address for non-guest users)

Copy link
Author

Choose a reason for hiding this comment

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

It works fine while the GAL is small.

Copy link
Member

Choose a reason for hiding this comment

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

Nice, does it filter as you type or not?

I think add it, and we can maybe modify as we go on. Is it an existing control/component - https://developer.microsoft.com/en-us/fluentui#/controls/web/peoplepicker ?

Copy link
Author

Choose a reason for hiding this comment

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

No it is a combobox with an API, will add it now and take a look at that link to see if I can get it in easily?

Copy link
Author

Choose a reason for hiding this comment

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

This is now replaced with the people picker

@jonnyry
Copy link
Collaborator

jonnyry commented Feb 14, 2025

NOTE: To use this feature the API Service principal needs to have 2 more application MS Graph permissions adding. Groups.ReadWrite.All and AppRoleAssignments.ReadWriteAll

Is there any way to use a narrower permission than AppRoleAssignments.ReadWriteAll? IIUC this is a broad permission with the ability to grant any other permission (e.g. global admin).

@marrobi
Copy link
Member

marrobi commented Feb 14, 2025

NOTE: To use this feature the API Service principal needs to have 2 more application MS Graph permissions adding. Groups.ReadWrite.All and AppRoleAssignments.ReadWriteAll

Is there any way to use a narrower permission than AppRoleAssignments.ReadWriteAll? IIUC this is a broad permission with the ability to grant any other permission (e.g. global admin).

The Resource Processor should already have access to these if it created them, maybe it should give the API access to the specific groups and app roles?

@fortunkam
Copy link
Author

NOTE: To use this feature the API Service principal needs to have 2 more application MS Graph permissions adding. Groups.ReadWrite.All and AppRoleAssignments.ReadWriteAll

Is there any way to use a narrower permission than AppRoleAssignments.ReadWriteAll? IIUC this is a broad permission with the ability to grant any other permission (e.g. global admin).

The Resource Processor should already have access to these if it created them, maybe it should give the API access to the specific groups and app roles?

In theory it should be owner on the groups so should be able to access the data but this was the only way we could get it to work. I think the ms graph layer was getting in the way but it needs more research.

@fortunkam fortunkam marked this pull request as ready for review February 17, 2025 10:06
@fortunkam fortunkam marked this pull request as draft February 19, 2025 14:03
@marrobi marrobi requested a review from Copilot February 19, 2025 15:31
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.

@fortunkam
Copy link
Author

Following discussion the User Management feature will now only be available on workspaces with AAD groups enabled.
The additional Graph API permissions are now not required.

@fortunkam fortunkam marked this pull request as ready for review February 21, 2025 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external PR from an external contributor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enable Workspace Owners to add multiple users and assign WorkspaceResearcher role
3 participants