diff --git a/mod_ood_proxy/lib/ood/user_map.lua b/mod_ood_proxy/lib/ood/user_map.lua index b5a8a6d914..3dbf02902c 100644 --- a/mod_ood_proxy/lib/ood/user_map.lua +++ b/mod_ood_proxy/lib/ood/user_map.lua @@ -17,6 +17,12 @@ function map(r, user_map_match, user_map_cmd, remote_user) handle:close() end + -- if sys_user is a number, then it's the uid, so convert to username + if tonumber(sys_user) then + local pwd = require "posix.pwd" + sys_user = pwd.getpwuid(tonumber(sys_user)).pw_name + end + time_user_map = (r:clock() - now)/1000.0 r:debug("Mapped '" .. remote_user .. "' => '" .. (sys_user or "") .. "' [" .. time_user_map .. " ms]") @@ -25,6 +31,7 @@ function map(r, user_map_match, user_map_cmd, remote_user) return nil end + r.subprocess_env['MAPPED_USER'] = sys_user -- set as CGI variable for later hooks (i.e., analytics) r.subprocess_env['OOD_TIME_USER_MAP'] = time_user_map -- set as CGI variable for later hooks (i.e., analytics) return sys_user diff --git a/nginx_stage/lib/nginx_stage/user.rb b/nginx_stage/lib/nginx_stage/user.rb index 0bef299f6d..6c0eb83d89 100644 --- a/nginx_stage/lib/nginx_stage/user.rb +++ b/nginx_stage/lib/nginx_stage/user.rb @@ -33,21 +33,37 @@ class User # @param user [String] the user name defining this object # @raise [ArgumentError] if user or primary group doesn't exist on local system def initialize(user) - @passwd = Etc.getpwnam user.to_s - @group = Etc.getgrgid gid - @groups = get_groups - - if name.to_s != user.to_s - err_msg = <<~HEREDOC - Username '#{user}' is being mapped to '#{name}' in SSSD and they don't match. - Users with domain names cannot be mapped correctly. If '#{name}' still has the - domain in it you'll need to set SSSD's full_name_format to '%1$s'. + # See if user is all numbers (potentially uid), regexp is 8% faster than integer conversion + # Benchmark: 0.13 microseconds per call (1M cycles) + if user.match?(/\A\d+\z/) + # The user is composed of all numbers, (numeric string) + # 10 microseconds per call if it matches + # 203 microseconds per call if it doesn't match (only happens if username is all numbers but not a uid) + begin + @passwd = Etc.getpwuid(user.to_i) + rescue ArgumentError + # We got a number as a username but we failed the lookup, fallthrough to the string lookup + end + end - See https://github.com/OSC/ondemand/issues/1759 for more details. - HEREDOC + # Variable is not set, so the user is a string + unless @passwd + # Benchmark: 13 microseconds per call (1M cycles) + @passwd = Etc.getpwnam(user) + if name.to_s != user.to_s + err_msg = <<~HEREDOC + Username '#{user}' is being mapped to '#{name}' in SSSD and they don't match. + Users with domain names cannot be mapped correctly. If '#{name}' still has the + domain in it you'll need to set SSSD's full_name_format to '%1$s'. + + See https://github.com/OSC/ondemand/issues/1759 for more details. + HEREDOC - raise StandardError, err_msg + raise StandardError, err_msg + end end + @group = Etc.getgrgid gid + @groups = get_groups end # User's primary group name @@ -79,7 +95,16 @@ def to_str # Use `id` to get list of groups as the /etc/group file can give # erroneous results def get_groups - `id -nG #{name}`.split(' ') + # Group names can contain spaces, prevent "domain users" people from being added to the "users" group + # We retrieve GIDs and convert to names (or GID) + `id -G #{name}`.split(' ').map(&:to_i).map do |gid| + begin + Etc.getgrgid(gid).name + rescue ArgumentError + # Still return the GID as a string if the group doesn't exist + gid.to_s + end + end end end end