Skip to content

Conversation

@QuanMPhm
Copy link
Contributor

@QuanMPhm QuanMPhm commented Oct 3, 2025

Closes nerc-project/operations#948. More details in the commit message
There are still some questions I have below, so this is still a draft for now.


def get_user_id(self, cf_username) -> str | None:
"""Return None if user not found"""
# TODO (Quan): Confirm that Coldfront usernames map to Keycloak emails, not email, or something else?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

user_id = self.kc_admin_client.get_user_id(user.username)
assert project_id in self.kc_admin_client.get_user_groups(user_id)

# TODO (Quan): Confirm that user should also be removed from group on role removal
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes

@QuanMPhm
Copy link
Contributor Author

QuanMPhm commented Oct 6, 2025

@knikolla Two more questions:

  1. Do we also want validate_allocations to add PIs to Keycloak groups for pre-existing allocations?
  2. When a PI adds a user to an Coldfront project or allocation, do those users also get added to a the project's Keycloak group?

@functools.cached_property
def api_client(self):
params = {
"grant_type": "password",
Copy link
Collaborator

Choose a reason for hiding this comment

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

See if you can use the client credentials flow instead of admin password here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With the current version of Keycloak being used for the integration test (25.0), the Keycloak container doesn't seem to have a way to easily configure a client with access to the REST API. I could write a CI script that calls the API to create said client. Based on the latest Keycloak documentation, another option could be to use a more up-to-date version of Keycloak, which has an option to configure an admin client?


allocator.set_quota(project_id)

# After setting everything on cluster, add user to Keycloak group
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function is growing too long (doing too many things) and I think there might a better place for the code in this block.

Perhaps the base class in base.py can abstract some of the duties, among create_project, get_or_create_federated_user and assign_role_on_user.

user_id = self.kc_admin_client.get_user_id(user.username)
assert project_id in self.kc_admin_client.get_user_groups(user_id)

# TODO (Quan): Confirm that user should also be removed from group on role removal
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes

@QuanMPhm
Copy link
Contributor Author

@knikolla I've addressed your comments except one. Also, do you have responses to these questions?

A Keycloak admin client has been added
When `activate_allocation` is called, the user is added
to a Keycloak group named after the project ID on the remote cluster.
If the user does not already exist in Keycloak, the case is ignored for now

When `deactivate_allocation` is called, the user is removed from the Keycloak group

Unit tests have been updated to remove dependancy on Keycloak

A comment in `validate_allocations` has been updated to
reflect the more restrictive validation behavior, where users on cluster projects
will be removed if they are not part of the Coldfront allocation (rather
than if they are registered on Coldfront at all). This is relevant
for functional tests for this new feature.
Comment on lines +40 to +54
def assign_role_on_user(self, username, project_id):
self.kc_admin_client.create_group(project_id)
if user_id := self.kc_admin_client.get_user_id(username):
group_id = self.kc_admin_client.get_group_id(project_id)
self.kc_admin_client.add_user_to_group(user_id, group_id)
else:
logger.warning(
f"User {username} not found in Keycloak, cannot add to group."
)

def remove_role_from_user(self, username, project_id):
user_id = self.kc_admin_client.get_user_id(username)
group_id = self.kc_admin_client.get_group_id(project_id)
self.kc_admin_client.remove_user_from_group(user_id, group_id)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@knikolla @naved001 The Openstack functional tests are failing because the plugin tries to add the coldfront-swift-init user to Openstack projects. The user is added to the cluster proejct, but since they're not registered on Keycloak, they're not added to the Keycloak group. This causes remove_role_from_user() in src/coldfront_plugin_cloud/base.py to raise an 404 error when it uses the Keycloak API to add a non-existant user to a group.

This can be resolved if we allow remove_role_from_user() to ignore if the user is not found, which was the agreed behavior for assign_role_on_user(). Is that acceptable?

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.

Investigate centralizing authorization for NERC users in Keycloak

2 participants