summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/user/ldap.rb
blob: 2e200a88e3f21d038b19535d30b5593d61231d7c (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
130
131
132
133
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
                if num > largest
                    largest = num
                end
            end
        end
        largest + 1
    end

    # Convert our gid to a group name, if necessary.
    def gid=(value)
        unless [Fixnum, Bignum].include?(value.class)
            value = group2id(value)
        end

        @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=%s" % name)
                return @property_hash[:groups] = :absent
            end

            return @property_hash[:groups] = result.collect { |r| r[:name] }.join(",")
        end
        return @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 %s" % 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