Skip to content
Snippets Groups Projects
Commit d860c382 authored by Jörn Künsemöller's avatar Jörn Künsemöller
Browse files

TMSS-911: Adaptation of implementation details to match latest changes (shared...

TMSS-911: Adaptation of implementation details to match latest changes (shared support primary role, project attributes in Keycloak, etc.)
parent 3992e42a
No related branches found
No related tags found
3 merge requests!634WIP: COBALT commissioning delta,!527TMSS-911: Adaptation of implementation details to match latest changes (shared...,!481Draft: SW-971 SW-973 SW-975: Various fixes to build LOFAR correctly.
......@@ -25,7 +25,7 @@ class TMSSOIDCAuthenticationBackend(OIDCAuthenticationBackend):
project_roles.append({'project': project_name, 'role': role_name})
else:
logger.error('could not handle entitlement=%s because no project role exists that matches the entitlement role=%s' % (entitlement, role_name))
elif ':' not in entitlement:
elif ':' not in project_entitlement:
# TMSS only has project roles, we interpret 'general' membership in a project as a co_i role,
# but may make that explicit in Keycloak later on
project_roles.append({'project': entitlement, 'role': 'co_i'})
......
......@@ -5,7 +5,7 @@ import os
import json
import re
from lofar.sas.tmss.tmss.exceptions import TMSSException
from lofar.sas.tmss.tmss.tmssapp import models
logger = logging.Logger(__name__)
KEYCLOAK_TOKEN_URL = os.environ.get('KEYCLOAK_TOKEN_URL', 'https://sdc-dev.astron.nl/auth/realms/master/protocol/openid-connect/token')
......@@ -45,7 +45,10 @@ def get_users_by_role_in_project(role, project):
returns the list of users that have the specified role in the specified project
"""
project_persons = get_project_persons()
return project_persons[project][role]
if project in project_persons:
return project_persons[project][role]
else:
[]
@cachetools.func.ttl_cache(ttl=600)
......@@ -64,29 +67,43 @@ def get_project_persons():
project_detail = ksession.get(url='%s/groups/%s/' % (KEYCLOAK_API_BASE_URL, project['id']))
attributes = project_detail.get('attributes', {})
role_keys = {'pi': 'lofarProjectPI',
'friend_of_project': 'lofarProjectFriend',
'contact': 'lofarProjectContactauthor'}
for role, key in role_keys.items():
users = attributes.get(key, [])
# convert user list to something we can use in TMSS
legacy_role_keys = {'pi': 'lofarProjectPI',
'friend_of_project': 'lofarProjectFriend',
'contact': 'lofarProjectContactauthor'}
for project_role in models.ProjectRole.Choices:
# get role attribute from project:
role = project_role.value
users = attributes.get(role, [])
# fall back to legacy-style attribute:
if not users and role in legacy_role_keys:
users = attributes.get(legacy_role_keys[role], [])
# convert user list (LDAP DNs) to something we can use in TMSS (email)
user_map = get_user_mapping()
# todo: find a way to replicate the exact string representation Keycloak uses (where to get the title from?), instead of the following unsafe hack
unmappable_users = [user for user in users if user not in user_map]
mapped_users = [user_map[user] for user in users if user in user_map]
mapped_users = [user_map[user] for user in users if user in user_map] # email list of referenced users
unmappable_users = [user for user in users if user not in user_map] # list of references for which no account was found
for unmappable_user in unmappable_users:
unmappable_user_fixed = re.sub('Dr\.', '', unmappable_user)
unmappable_user_fixed = re.sub('Prof\.', '', unmappable_user_fixed)
unmappable_user_fixed = re.sub('ir\.', '', unmappable_user_fixed)
unmappable_user_fixed = re.sub('Ir\.', '', unmappable_user_fixed)
unmappable_user_fixed = re.sub('apl\.', '', unmappable_user_fixed)
unmappable_user_fixed = re.sub(' +', ' ', unmappable_user_fixed)
if unmappable_user_fixed in user_map:
mapped_users.append(user_map[unmappable_user_fixed])
else:
logger.warning("Could not match Keycloak user reference '%s' to a known user. Will " % unmappable_user)
mapped_users.append(unmappable_user)
# Note: Usually Keycloak should return DN references to user accounts. For PI's, someone had the
# great idea to allow to specify a freeform string instead, to refer to people who may or may not
# have an account. Even if the person has a user account, there is no way to replicate the exact
# string 'representation' Keycloak returns, since the string may contain typos, or info that is not
# stored in the user accounts (like titles).
# The following unsafe hack tries to determine whether there is a user account that matches the
# name given in the string (ignore titles since they are not part of the user account):
# unmappable_user_fixed = re.sub('Dr\.', '', unmappable_user)
# unmappable_user_fixed = re.sub('Prof\.', '', unmappable_user_fixed)
# unmappable_user_fixed = re.sub('ir\.', '', unmappable_user_fixed)
# unmappable_user_fixed = re.sub('Ir\.', '', unmappable_user_fixed)
# unmappable_user_fixed = re.sub('apl\.', '', unmappable_user_fixed)
# unmappable_user_fixed = re.sub(' +', ' ', unmappable_user_fixed)
#
# if unmappable_user_fixed in user_map:
# mapped_users.append(user_map[unmappable_user_fixed])
# else:
logger.warning("Could not match Keycloak user reference '%s' to a known user." % unmappable_user)
if not unmappable_user.startswith('cn='):
logger.warning("LOFAR allowed to reference a person by a freeform string instead of a user account. '%s' seems to be such a legacy reference. This needs to be fixed in the identity management." % unmappable_user)
project_persons_map.setdefault(project['name'], {})[role] = mapped_users
return project_persons_map
......
......@@ -36,6 +36,7 @@ class ProjectRole(AbstractChoice):
CO_I = "co_i"
CONTACT_AUTHOR = "contact"
SHARED_SUPPORT = 'shared_support'
SHARED_SUPPORT_PRIMARY = 'shared_support_primary'
FRIEND_OF_PROJECT = 'friend_of_project'
FRIEND_OF_PROJECT_PRIMARY = 'friend_of_project_primary'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment