You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by se...@apache.org on 2021/07/07 22:20:34 UTC

[whimsy] branch master updated: Improve nextuid code to detect gaps in allocation

This is an automated email from the ASF dual-hosted git repository.

sebb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/whimsy.git


The following commit(s) were added to refs/heads/master by this push:
     new da401d9  Improve nextuid code to detect gaps in allocation
da401d9 is described below

commit da401d900d40bd482951c388476db2606c4588e1
Author: Sebb <se...@apache.org>
AuthorDate: Wed Jul 7 23:20:25 2021 +0100

    Improve nextuid code to detect gaps in allocation
    
    It requires an expensive search to set up, so optionally
    allow retrieval of multiple free ids
    
    Also force user to change password as per current
    practice
---
 lib/whimsy/asf/ldap.rb | 54 +++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 42 insertions(+), 12 deletions(-)

diff --git a/lib/whimsy/asf/ldap.rb b/lib/whimsy/asf/ldap.rb
index 75e7917..fc2f536 100644
--- a/lib/whimsy/asf/ldap.rb
+++ b/lib/whimsy/asf/ldap.rb
@@ -914,6 +914,38 @@ module ASF
       end
     end
 
+    MINIMUM_USER_UID = 6000 # from asfpy/ldap
+    # Return the next free value for use as uidNumber/gidNumber
+    # Optionally return several free values as an array
+    def self.next_uidNumber(count=1)
+      raise ArgumentError.new "Count: #{count} is less than 1!" if count < 1
+      numbers = ASF::search_one(ASF::Person.base, 'uid=*', ['uidNumber', 'gidNumber']).
+        map{|i| u=i['uidNumber'];g=i['gidNumber']; u == g ? u : [u,g]}.flatten.map(&:to_i).
+        select{|i| i >= MINIMUM_USER_UID}.uniq.sort.lazy
+      enum = Enumerator.new do |output|
+        last = numbers.next rescue MINIMUM_USER_UID # in case no valid entries exist
+        loop do
+            curr = numbers.next
+            if curr <= last + 1
+              last = curr
+            else
+                (last+1..curr-1).each {|i| output << i}
+                last = curr
+            end
+        end
+        # in case we ran off the end...
+        loop do
+          last = last+1
+          output << last
+        end
+      end
+      if (count == 1)
+        enum.first
+      else
+        enum.take(count)
+      end
+    end
+
     # add a new person to LDAP.  Attrs must include uid, cn, and mail
     def self.add(attrs)
       # convert keys to strings
@@ -929,9 +961,12 @@ module ASF
       availid = attrs['uid']
 
       # determine next uid and group, unless provided
-      nextuid = attrs['uidNumber'] ||
-        ASF::search_one(ASF::Person.base, 'uid=*', 'uidNumber').
-          flatten.map(&:to_i).max + 1
+      nextuid = attrs['uidNumber']
+      if nextuid
+        raise ArgumentError.new("gidNumber #{gidNumber} != uidNumber #{uidNumber}") unless attrs['gidNumber'] == nextuid
+      else
+        nextuid = next_uidNumber
+      end
 
       # fixed attributes
       attrs.merge!({
@@ -943,7 +978,7 @@ module ASF
       })
 
       # defaults
-      attrs['loginShell'] ||= '/usr/local/bin/bash'
+      attrs['loginShell'] ||= '/bin/bash' # as per asfpy.ldap
       attrs['homeDirectory'] ||= File.join("/home", availid)
       attrs['host'] ||= "home.apache.org"
       attrs['asf-sascore'] ||= "10"
@@ -951,20 +986,15 @@ module ASF
       # parse name if sn has not been provided (givenName is optional)
       attrs = ASF::Person.ldap_name(attrs['cn']).merge(attrs) unless attrs['sn']
 
-      # generate a password that is between 8 and 16 alphanumeric characters
-      unless attrs['userPassword']
-        while attrs['userPassword'].to_s.length < 8
-          attrs['userPassword'] = SecureRandom.base64(12).gsub(/\W+/, '')
-        end
-      end
+      # user is expected to use id.apache.org to set their initial password
+      attrs['userPassword'] = '{CRYPT}*' # invalid password (I assume)
 
       # create new LDAP person
       entry = attrs.map {|key, value| mod_add(key, value)}
       ASF::LDAP.add("uid=#{availid},#{base}", entry)
 
-      # return person object with password filled in
+      # return person object; they must use id.apache.org to reset the password
       person = ASF::Person.find(availid)
-      person.attrs['userPassword'] = [attrs['userPassword']]
       person
     end