require 'puppet/provider/ldap' Puppet::Type.type(:user).provide :ldap, :parent => Puppet::Provider::Ldap do desc "User management via LDAP. This provider requires that you have valid values for all of the LDAP-related settings in `puppet.conf`, including `ldapbase`. You will almost definitely need settings for `ldapuser` and `ldappassword` in order for your clients to write to LDAP. Note that this provider will automatically generate a UID for you if you do not specify one, but it is a potentially expensive operation, as it iterates across all existing users to pick the appropriate next one." confine :feature => :ldap, :false => (Puppet[:ldapuser] == "") has_feature :manages_passwords manages(:posixAccount, :person).at("ou=People").named_by(:uid).and.maps :name => :uid, :password => :userPassword, :comment => :cn, :uid => :uidNumber, :gid => :gidNumber, :home => :homeDirectory, :shell => :loginShell # Use the last field of a space-separated array as # the sn. LDAP requires a surname, for some stupid reason. manager.generates(:sn).from(:cn).with do |cn| cn[0].split(/\s+/)[-1] end # Find the next uid after the current largest uid. provider = self manager.generates(:uidNumber).with do largest = 500 if existing = provider.manager.search existing.each do |hash| next unless value = hash[:uid] num = value[0].to_i largest = num if num > largest end end largest + 1 end # Convert our gid to a group name, if necessary. def gid=(value) value = group2id(value) unless [Fixnum, Bignum].include?(value.class) @property_hash[:gid] = value end # Find all groups this user is a member of in ldap. def groups # We want to cache the current result, so we know if we # have to remove old values. unless @property_hash[:groups] unless result = group_manager.search("memberUid=#{name}") return @property_hash[:groups] = :absent end return @property_hash[:groups] = result.collect { |r| r[:name] }.sort.join(",") end @property_hash[:groups] end # Manage the list of groups this user is a member of. def groups=(values) should = values.split(",") if groups == :absent is = [] else is = groups.split(",") end modes = {} [is, should].flatten.uniq.each do |group| # Skip it when they're in both next if is.include?(group) and should.include?(group) # We're adding a group. modes[group] = :add and next unless is.include?(group) # We're removing a group. modes[group] = :remove and next unless should.include?(group) end modes.each do |group, form| self.fail "Could not find ldap group #{group}" unless ldap_group = group_manager.find(group) current = ldap_group[:members] if form == :add if current.is_a?(Array) and ! current.empty? new = current + [name] else new = [name] end else new = current - [name] new = :absent if new.empty? end group_manager.update(group, {:ensure => :present, :members => current}, {:ensure => :present, :members => new}) end end # Convert a gropu name to an id. def group2id(group) Puppet::Type.type(:group).provider(:ldap).name2id(group) end private def group_manager Puppet::Type.type(:group).provider(:ldap).manager end def group_properties(values) if values.empty? or values == :absent {:ensure => :present} else {:ensure => :present, :members => values} end end end