Class: Scooter::LDAP::LDAPDispatcher

Inherits:
Net::LDAP
  • Object
show all
Defined in:
lib/scooter/ldap.rb

Overview

Quick-start guide for the impatient

Quick example creating an LDAPDispatcher object with a beaker config:

#Example beaker configuration
#
#HOSTS:
#  win_2008_r2_x64:
#    roles:
#      - directory_service
#    platform: windows-2008r2-x86_64

require 'scooter'
ldapdispatcher = Scooter::LDAP::LDAPDispatcher.new(directory_service)
# If you are not using the default static fixtures, you probably want
# to change the credentials for your LDAP instance
ldapdispatcher.auth(user_dn, password)
# This is the normal method you would use to set up a standard test
# environment, with groups of writers(poets, lyricists, novelists)
# to populate your directory_service
ldapdispatcher.create_default_test_groups_and_users

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, options = {}) ⇒ LDAPDispatcher

Instantiating an object of type Scooter::LDAP::LDAPDispatcher extends the Net::LDAP class to include helper methods to make test setup and cleanup more consistent and reliable for beaker tests involving the Puppet RBAC Service. LDAPDispatcher objects require either a Unix::Host or Windows::Host object passed in as a parameter, which will dictate how helper methods construct a test environment of groups and users.

Unlike the Net::LDAP, LDAPDispatcher does test the network connection during initialization and raises a warning if it fails.

Parameters:

  • host (Unix::Host, Windows::Host)

    the DS host object defined in your Beaker config

  • options (hash) (defaults to: {})

    any params you would like to override; you are likely to want to do this if you are not using the static Puppet LDAP fixtures



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
# File 'lib/scooter/ldap.rb', line 50

def initialize(host, options={})
  
  # All initialized LDAPDispatcher objects will have test_uids to ensure
  # no collisions when creating entries in the directory services.
  @test_uid = Scooter::Utilities::RandomString.generate(4)
  if host.is_a? Windows::Host
    @ds_type = :ad
  elsif host.is_a? Unix::Host
    @ds_type = :openldap
  else
    raise "host must be Unix::Host or Windows::Host, not #{host.class}"
  end

  generated_args = {}
  generated_args[:host] = host.reachable_name
  generated_args[:port] = DEFAULT_DS_PORT
  generated_args[:encryption] = {:method => :simple_tls}
  generated_args[:base] = return_default_base

  generated_args.merge!(options)
  super(generated_args)

  # If we didn't pass in an :auth hash, generate the default settings
  # using the auth method of Net::LDAP
  if !options[:auth]
    self.auth admin_dn, return_default_password
  end

  if !bind
    warn "Problem binding to #{host}, #{get_operation_result}\n
          username: #{admin_dn}, pw: #{return_default_password}"
  end
end

Instance Attribute Details

#ds_typeObject (readonly)

Returns the value of attribute ds_type.



34
35
36
# File 'lib/scooter/ldap.rb', line 34

def ds_type
  @ds_type
end

#ds_usersObject (readonly)

Returns the value of attribute ds_users.



34
35
36
# File 'lib/scooter/ldap.rb', line 34

def ds_users
  @ds_users
end

#groups_dnObject (readonly)

Returns the value of attribute groups_dn.



34
35
36
# File 'lib/scooter/ldap.rb', line 34

def groups_dn
  @groups_dn
end

#test_uidObject

Returns the value of attribute test_uid.



33
34
35
# File 'lib/scooter/ldap.rb', line 33

def test_uid
  @test_uid
end

#users_dnObject (readonly)

Returns the value of attribute users_dn.



34
35
36
# File 'lib/scooter/ldap.rb', line 34

def users_dn
  @users_dn
end

Instance Method Details

#admin_dnObject



100
101
102
103
104
105
106
# File 'lib/scooter/ldap.rb', line 100

def admin_dn
  if is_windows_ad?
    "cn=Administrator,cn=Users,#{return_default_base}"
  else
    "cn=admin,#{return_default_base}"
  end
end

#create_default_test_groups_and_usersObject

This is the primary method most tests will use. It creates two organizational units, or ou’s, to base all your testing around. There is one ou for groups and one for users. Most testing can be covered by simply running the method create_default_test_groups_and_users.



207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/scooter/ldap.rb', line 207

def create_default_test_groups_and_users

  create_ou_for_users_and_groups

  create_default_users

  if is_windows_ad?
    create_windows_ad_default_users_and_test_groups
  elsif is_openldap?
    create_openldap_default_users_and_test_groups
  end

end

#create_default_usersObject



221
222
223
224
225
226
227
228
229
230
# File 'lib/scooter/ldap.rb', line 221

def create_default_users
  users = Scooter::LDAP::LDAPFixtures.users(@test_uid)

  users.each do |name, hash|
    create_ds_user(hash)
    update_user_password("CN=#{hash[:cn]},#{users_dn}", DEFAULT_USER_PASSWORD)
    hash[:password] = DEFAULT_USER_PASSWORD
  end
  @ds_users = users
end

#create_ds_group(attributes, groups_dn = self.groups_dn) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/scooter/ldap.rb', line 178

def create_ds_group(attributes, groups_dn=self.groups_dn)

  #When Openldap, you must specify :member entries in the attributes
  default_attributes = {:objectClass => ["top", "groupOfUniqueNames"]}

  if is_windows_ad?
    default_attributes[:objectClass] = ["top", "group"]
  end

  default_attributes.merge!(attributes)

  add(:dn => "cn=#{default_attributes[:cn]},#{groups_dn}",
      :attributes => default_attributes)

  if get_operation_result.code != 0
    raise "Creating group failed: #{get_operation_result},\n
          #{default_attributes}"
  end
end

#create_ds_user(attributes, users_dn = self.users_dn) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/scooter/ldap.rb', line 157

def create_ds_user(attributes, users_dn=self.users_dn)
  default_attributes = {:objectClass => ['top',
                                         'person',
                                         'organizationalPerson',
                                         'inetOrgPerson']}

  if is_windows_ad?
    default_attributes[:userAccountControl] = ['544']
  end

  default_attributes.merge!(attributes)

  add(:dn => "cn=#{default_attributes[:cn]},#{users_dn}",
      :attributes => default_attributes)

  if get_operation_result.code != 0
    raise "Creating user failed: #{get_operation_result}\n
          #{default_attributes}"
  end
end

#create_ou_for_users_and_groupsObject



198
199
200
201
# File 'lib/scooter/ldap.rb', line 198

def create_ou_for_users_and_groups
  @users_dn = create_temp_ou('users')
  @groups_dn = create_temp_ou('groups')
end

#create_temp_ou(base_string = 'test_') ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/scooter/ldap.rb', line 108

def create_temp_ou(base_string='test_')
  ou = base_string + @test_uid
  dn = "ou=#{ou},#{self.base}"
  attr = {:objectClass => ['top', 'organizationalUnit'],
          :ou => ou}
  add(:dn => dn, :attributes => attr)

  if get_operation_result.code != 0
    raise "OU creation failed: #{get_operation_result}, #{dn}"
  end

  dn
end

#delete_all_dn_entries(dn) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/scooter/ldap.rb', line 137

def delete_all_dn_entries(dn)
  entries = search(:base => dn, :attributes => ['dn'])
  entries.each do |entry|
    delete :dn => entry.dn
  end

  #This needs to be repeated because it may have failed deleting a group
  #that still had users associated.
  entries.each do |entry|
    delete :dn => entry.dn
  end

  #This request should return nil; all entities with the dn provided
  #should now be deleted.
  entries = search(:base => dn, :attributes => ['dn'])
  if entries != nil
    raise "Problem deleting all entries for this dn: #{dn}"
  end
end

#delete_users_and_groups_organizational_unitsObject

This method should execute after a test’s completion; the group’s ou and users’s ou will be deleted, as will any entity with those respective ou’s in their distinguished name.

Example beaker teardown

Example beaker teardown

teardown do
  ldapdispatcher.delete_users_and_groups_organizational_units
end


132
133
134
135
# File 'lib/scooter/ldap.rb', line 132

def delete_users_and_groups_organizational_units
  delete_all_dn_entries(@groups_dn)
  delete_all_dn_entries(@users_dn)
end

#is_openldap?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/scooter/ldap.rb', line 92

def is_openldap?
  true if @ds_type == :openldap
end

#is_windows_ad?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/scooter/ldap.rb', line 96

def is_windows_ad?
  true if @ds_type == :ad
end

#return_default_baseObject



88
89
90
# File 'lib/scooter/ldap.rb', line 88

def return_default_base
  'dc=delivery,dc=puppetlabs,dc=net'
end

#return_default_passwordObject



84
85
86
# File 'lib/scooter/ldap.rb', line 84

def return_default_password
  "Puppet11"
end

#str_to_unicode_pwd(str) ⇒ Object

This is used to encode passwords for Windows AD See URL: msdn.microsoft.com/en-us/library/cc223248.aspx



234
235
236
# File 'lib/scooter/ldap.rb', line 234

def str_to_unicode_pwd(str) #:nodoc:
  ('"' + str + '"').encode("utf-16le").force_encoding("utf-8")
end

#update_user_password(user_dn, password) ⇒ Object

:nodoc:



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/scooter/ldap.rb', line 238

def update_user_password(user_dn, password) #:nodoc:
  if is_windows_ad?
    password = str_to_unicode_pwd(password)
    ops = [[:replace, :unicodePwd, password]]
  else
    ops = [[:replace, :userPassword, password]]
  end

  modify :dn => user_dn, :operations => ops

  if get_operation_result.code != 0
    raise "Updating password failed: #{get_operation_result}\n
          #{ops}"
  end
end