Skip to content

Commit

Permalink
ldap: sync ldap into names
Browse files Browse the repository at this point in the history
* closes #193
  • Loading branch information
jrcastro2 committed Sep 19, 2024
1 parent c945671 commit 75f970d
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// This file is part of CDS RDM
// Copyright (C) 2024 CERN.
//
// CDS RDM is free software; you can redistribute it and/or modify it
// under the terms of the MIT License; see LICENSE file for more details.

import _get from "lodash/get";
import _truncate from "lodash/truncate";
import _upperCase from "lodash/upperCase";
import React from "react";
import PropTypes from "prop-types";
import { Header, Image } from "semantic-ui-react";

export const CDSCreatibutorsRemoteSelectItem = ({ creatibutor, isOrganization, idString, affNames }) => {

if (creatibutor.props?.is_cern) {
const cmp = (
<span key={creatibutor.props.email}>
<Image
src="/static/images/CERN-logo.svg"
className="inline-id-icon ml-5 mr-5"
verticalAlign="middle"
/>
{creatibutor.props.email}
</span>
)
idString.push(cmp)
}

return (
<Header>
{creatibutor.name} {idString.length ? <>({idString})</> : null}
<Header.Subheader>
{isOrganization ? creatibutor.acronym : affNames}
</Header.Subheader>
</Header>
);
};

CDSCreatibutorsRemoteSelectItem.propTypes = {
creatibutor: PropTypes.object.isRequired,
isOrganization: PropTypes.bool.isRequired,
idString: PropTypes.array,
affNames: PropTypes.string,
};

CDSCreatibutorsRemoteSelectItem.defaultProps = {
idString: [],
affNames: "",
};
2 changes: 2 additions & 0 deletions assets/js/invenio_app_rdm/overridableRegistry/mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { CDSCarouselItem } from "../../components/communities_carousel/overrides
import { CDSCommunitiesCarousel } from "../../components/communities_carousel/overrides/CommunitiesCarousel";
import { CDSRecordsList } from "../../components/frontpage/overrides/RecordsList";
import { CDSRecordsResultsListItem } from "../../components/frontpage/overrides/RecordsResultsListItem";
import { CDSCreatibutorsRemoteSelectItem } from "../../components/deposit/overrides/CreatibutorsRemoteSelectItem";

export const overriddenComponents = {
"InvenioAppRdm.RecordsList.layout": CDSRecordsList,
"InvenioAppRdm.RecordsResultsListItem.layout": CDSRecordsResultsListItem,
"InvenioCommunities.CommunitiesCarousel.layout": CDSCommunitiesCarousel,
"InvenioCommunities.CarouselItem.layout": CDSCarouselItem,
"CreatibutorsModal.RemoteSelectItem.content": CDSCreatibutorsRemoteSelectItem,
};
13 changes: 12 additions & 1 deletion site/cds_rdm/ldap/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from invenio_users_resources.services.users.tasks import reindex_users

from cds_rdm.ldap.client import LdapClient
from cds_rdm.ldap.user_importer import LdapUserImporter
from cds_rdm.ldap.user_importer import LdapUserImporter, update_or_create_names_vocabularies
from cds_rdm.ldap.utils import InvenioUser, serialize_ldap_user, user_exists


Expand Down Expand Up @@ -102,6 +102,17 @@ def update_invenio_users_from_ldap(remote_accounts, ldap_users_map, log_func):

if has_changed:
invenio_user.update(ldap_user)
try:
update_or_create_names_vocabularies(ldap_user)
except Exception as e:
log_func(
"update_names_vocabularies_error",
dict(
user_id=invenio_user.user_id,
person_id=ldap_user["remote_account_person_id"],
),
is_error=True,
)
user_ids.append(invenio_user.user_id)
db.session.commit()
log_func(
Expand Down
2 changes: 2 additions & 0 deletions site/cds_rdm/ldap/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class LdapClient(object):
"uidNumber",
"cn",
"name",
"sn",
"givenName",
]

def __init__(self, ldap_url=None):
Expand Down
42 changes: 41 additions & 1 deletion site/cds_rdm/ldap/user_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,46 @@
from invenio_db import db
from invenio_oauthclient.models import RemoteAccount, UserIdentity
from invenio_userprofiles.models import UserProfile
from invenio_records_resources.proxies import current_service_registry
from invenio_access.permissions import system_identity
from sqlalchemy.orm.exc import NoResultFound


def update_or_create_names_vocabularies(ldap_user):
"""Update names vocabularies."""
names_service = current_service_registry.get("names")
name_data = {
"id": ldap_user["remote_account_person_id"],
"name": ldap_user["user_profile_full_name"],
"given_name": ldap_user["given_name"],
"family_name": ldap_user["family_name"],
"props": {
"email": ldap_user["user_email"],
"username": ldap_user["user_username"],
"department": ldap_user["remote_account_department"],
"is_cern": True,
},
"affiliations": [{"name": "CERN"}],
}

try:
fetched_name = names_service.read(system_identity, ldap_user["remote_account_person_id"])
# Determine if any updates are necessary
fetched_name_dict = fetched_name.to_dict()
update_needed = False
for key, value in name_data.items():
if key not in fetched_name_dict or fetched_name_dict[key] != value:
update_needed = True
break

# Perform update only if necessary
if update_needed:
name = names_service.update(system_identity, fetched_name.id, name_data)
except NoResultFound:
name = names_service.create(system_identity, name_data)

return name

class LdapUserImporter:
"""Import ldap users to Invenio RDM records.
Expand Down Expand Up @@ -70,7 +108,7 @@ def create_invenio_remote_account(self, user_id, ldap_user):
keycloak_id=keycloak_id, person_id=employee_id, department=department
),
)

def import_user(self, ldap_user):
"""Create Invenio users from LDAP export."""
user = self.create_invenio_user(ldap_user)
Expand All @@ -85,6 +123,8 @@ def import_user(self, ldap_user):
remote_account = self.create_invenio_remote_account(user_id, ldap_user)
db.session.add(remote_account)

update_or_create_names_vocabularies(ldap_user)

# Automatically confirm the user
confirm_user(user)
return user_id
14 changes: 14 additions & 0 deletions site/cds_rdm/ldap/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from invenio_userprofiles import UserProfile

from cds_rdm.ldap.errors import InvalidLdapUser
import hashlib


def serialize_ldap_user(ldap_user_data, log_func=None):
Expand All @@ -33,6 +34,8 @@ def serialize(ldap_user_data):
cern_account_type=decoded_data["cernAccountType"],
remote_account_person_id=str(decoded_data["employeeID"]),
remote_account_department=decoded_data["department"],
family_name=decoded_data["sn"],
given_name=decoded_data["givenName"],
)

return serialized_data
Expand Down Expand Up @@ -125,3 +128,14 @@ def update(self, ldap_user):
self.user.email = ldap_user["user_email"]
self.user.username = ldap_user["user_username"]
self.user_profile.full_name = ldap_user["user_profile_full_name"]


def hash_value(value, length=16):
"""Return a hashed version of the value."""
# TODO: we should use a secret to encrypt the value (the repo is public)
value_bytes = value.encode('utf-8')
hash_object = hashlib.sha256()
hash_object.update(value_bytes)
hashed_id = hash_object.hexdigest()[:length]

return hashed_id

0 comments on commit 75f970d

Please sign in to comment.