Skip to content

Commit

Permalink
NAS-129735 / 24.10 / Force directory service cache insertion on share…
Browse files Browse the repository at this point in the history
… ACL read (#13926)

There are various situations in our backend where we (for UI
convenience) add user / group names to returned ACL entries. This
commit changes behavior for when we retrieve these to perform
cache insertion for directory services so that they are always
available in dropdowns for UI consumers. This does not fully
ameliorate caching issues where enumeration of LDAP and AD users is
disabled, and so results of user.query and group.query should not
be considered authoritative for accounts that are external to
TrueNAS.
  • Loading branch information
anodos325 authored Jun 25, 2024
1 parent 76496aa commit 72f4c5e
Showing 1 changed file with 30 additions and 16 deletions.
46 changes: 30 additions & 16 deletions src/middlewared/middlewared/plugins/idmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from middlewared.schema import accepts, Bool, Dict, Int, Password, Patch, Ref, Str, LDAP_DN, OROperator
from middlewared.service import CallError, CRUDService, job, private, ValidationErrors, filterable
from middlewared.service_exception import MatchNotFound
from middlewared.utils.directoryservices.constants import SSL
from middlewared.plugins.idmap_.idmap_constants import (
IDType, SID_LOCAL_USER_PREFIX, SID_LOCAL_GROUP_PREFIX, TRUENAS_IDMAP_MAX
Expand Down Expand Up @@ -1081,35 +1082,48 @@ async def builtins(self, filters, options):
return filter_list(out, filters, options)

@private
async def id_to_name(self, id_, id_type):
async def id_to_name(self, xid, id_type):
"""
Helper method to retrieve the name for the specified uid or gid. This method
passes through user.query or group.query rather than user.get_user_obj or
group.get_group_obj because explicit request for a uid / gid will trigger
a directory service cache insertion if it does not already exist. This allows
some lazily fill cache if enumeration for directory services is disabled.
"""
idtype = IDType[id_type]
idmap_timeout = 5.0

if idtype == IDType.GROUP or idtype == IDType.BOTH:
method = "group.get_group_obj"
to_check = {"gid": id_}
key = 'gr_name'
elif idtype == IDType.USER:
method = "user.get_user_obj"
to_check = {"uid": id_}
key = 'pw_name'
else:
raise CallError(f"Unsupported id_type: [{idtype.name}]")
options = {'extra': {'additional_information': ['DS']}, 'get': True}

match idtype:
# IDType.BOTH is possible return by nss_winbind / nss_sss
# and is special case when idmapping backend converts a SID
# to both a user and a group. For most practical purposes it
# can be treated interally as a group.
case IDType.GROUP | IDType.BOTH:
method = 'group.query'
filters = [['gid', '=', xid]]
key = 'group'
case IDType.USER:
method = 'user.query'
filters = [['uid', '=', xid]]
key = 'username'
case _:
raise CallError(f"Unsupported id_type: [{idtype.name}]")

try:
ret = await asyncio.wait_for(
self.middleware.create_task(self.middleware.call(method, to_check)),
self.middleware.create_task(self.middleware.call(method, filters, options)),
timeout=idmap_timeout
)
name = ret[key]
except asyncio.TimeoutError:
self.logger.debug(
"timeout encountered while trying to convert %s id %s "
"timeout encountered while trying to convert %s id %d "
"to name. This may indicate significant networking issue.",
id_type.lower(), id_
id_type.lower(), xid
)
name = None
except KeyError:
except MatchNotFound:
name = None

return name
Expand Down

0 comments on commit 72f4c5e

Please sign in to comment.