summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/user/ldap.rb
blob: 75a9667b3d7bc838eec4b6fd946bd62f9722db66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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,
    including `ldapbase`.  You will also almost definitely need settings
    for `ldapuser` and `ldappassword`, so that your clients can 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|
    x = 1
    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