activeldap 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/Gemfile +1 -14
  2. data/benchmark/README.md +64 -0
  3. data/benchmark/{bench-al.rb → bench-backend.rb} +6 -22
  4. data/benchmark/bench-instantiate.rb +98 -0
  5. data/benchmark/config.yaml.sample +2 -2
  6. data/doc/text/news.textile +38 -0
  7. data/lib/active_ldap.rb +17 -8
  8. data/lib/active_ldap/association/has_many_wrap.rb +15 -2
  9. data/lib/active_ldap/attribute_methods.rb +23 -0
  10. data/lib/active_ldap/attribute_methods/before_type_cast.rb +24 -0
  11. data/lib/active_ldap/attribute_methods/dirty.rb +43 -0
  12. data/lib/active_ldap/attribute_methods/query.rb +31 -0
  13. data/lib/active_ldap/attribute_methods/read.rb +44 -0
  14. data/lib/active_ldap/attribute_methods/write.rb +38 -0
  15. data/lib/active_ldap/attributes.rb +18 -26
  16. data/lib/active_ldap/base.rb +42 -163
  17. data/lib/active_ldap/connection.rb +6 -1
  18. data/lib/active_ldap/get_text.rb +18 -7
  19. data/lib/active_ldap/operations.rb +63 -49
  20. data/lib/active_ldap/persistence.rb +17 -0
  21. data/lib/active_ldap/railtie.rb +3 -0
  22. data/lib/active_ldap/schema.rb +2 -0
  23. data/lib/active_ldap/schema/syntaxes.rb +7 -7
  24. data/lib/active_ldap/validations.rb +2 -2
  25. data/lib/active_ldap/version.rb +3 -0
  26. data/lib/active_ldap/xml.rb +24 -7
  27. data/lib/rails/generators/active_ldap/model/model_generator.rb +3 -3
  28. data/test/add-phonetic-attribute-options-to-slapd.ldif +10 -0
  29. data/test/al-test-utils.rb +428 -0
  30. data/test/command.rb +111 -0
  31. data/test/config.yaml.sample +6 -0
  32. data/test/fixtures/lower_case_object_class_schema.rb +802 -0
  33. data/test/run-test.rb +29 -0
  34. data/test/test_associations.rb +37 -0
  35. data/test/test_base.rb +113 -51
  36. data/test/test_dirty.rb +84 -0
  37. data/test/test_ldif.rb +0 -1
  38. data/test/test_load.rb +0 -1
  39. data/test/test_reflection.rb +7 -14
  40. data/test/test_syntax.rb +104 -43
  41. data/test/test_usermod-binary-del.rb +1 -1
  42. data/test/test_usermod-lang-add.rb +0 -1
  43. metadata +272 -224
  44. data/lib/active_ldap/get_text_fallback.rb +0 -60
  45. data/lib/active_ldap/get_text_support.rb +0 -22
@@ -167,6 +167,7 @@ module ActiveLdap
167
167
 
168
168
  def reset_runtime
169
169
  active_connections.inject(0) do |result, (name, connection)|
170
+ _ = name # for suppress a warning on Ruby 1.9.3
170
171
  result + connection.reset_runtime
171
172
  end
172
173
  end
@@ -211,7 +212,7 @@ module ActiveLdap
211
212
  end
212
213
  end
213
214
  if !ruby_ldap_available and Object.const_defined?(:Gem)
214
- ruby_ldap_available = Gem.available?("ruby-ldap")
215
+ ruby_ldap_available = gem_available?("ruby-ldap")
215
216
  end
216
217
  if ruby_ldap_available
217
218
  "ldap"
@@ -220,6 +221,10 @@ module ActiveLdap
220
221
  end
221
222
  end
222
223
  end
224
+
225
+ def gem_available?(name)
226
+ not Gem::Specification.find_all_by_name(name).empty?
227
+ end
223
228
  end
224
229
 
225
230
  def setup_connection(config=nil)
@@ -1,9 +1,20 @@
1
- if Object.const_defined?(:FastGettext)
2
- ActiveLdap.const_set("GetText", FastGettext)
3
- end
1
+ require "gettext"
4
2
 
5
- unless ActiveLdap.const_defined?(:GetText)
6
- require 'active_ldap/get_text_fallback'
7
- end
3
+ module ActiveLdap
4
+ class << self
5
+ def get_text_supported?
6
+ true
7
+ end
8
+ end
8
9
 
9
- require 'active_ldap/get_text_support'
10
+ module GetTextSupport
11
+ class << self
12
+ def included(base)
13
+ base.class_eval do
14
+ include(GetText)
15
+ bindtextdomain("active-ldap")
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -8,7 +8,9 @@ module ActiveLdap
8
8
  extend(Find)
9
9
  extend(LDIF)
10
10
  extend(Delete)
11
+ extend(ClassOnlyDelete)
11
12
  extend(Update)
13
+ extend(ClassOnlyUpdate)
12
14
 
13
15
  include(Common)
14
16
  include(Find)
@@ -22,7 +24,7 @@ module ActiveLdap
22
24
  module Common
23
25
  VALID_SEARCH_OPTIONS = [:attribute, :value, :filter, :prefix,
24
26
  :classes, :scope, :limit, :attributes,
25
- :sort_by, :order, :connection, :base]
27
+ :sort_by, :order, :connection, :base, :offset]
26
28
 
27
29
  def search(options={}, &block)
28
30
  validate_search_options(options)
@@ -31,6 +33,7 @@ module ActiveLdap
31
33
  filter = options[:filter]
32
34
  prefix = options[:prefix]
33
35
  classes = options[:classes]
36
+ requested_attributes = options[:attributes]
34
37
 
35
38
  value = value.first if value.is_a?(Array) and value.first.size == 1
36
39
 
@@ -56,20 +59,25 @@ module ActiveLdap
56
59
  :scope => options[:scope] || scope,
57
60
  :filter => filter,
58
61
  :limit => options[:limit],
59
- :attributes => options[:attributes],
62
+ :attributes => requested_attributes,
60
63
  :sort_by => options[:sort_by] || sort_by,
61
64
  :order => options[:order] || order,
62
65
  }
63
-
64
66
  options[:connection] ||= connection
65
67
  values = []
68
+ requested_all_attributes_p =
69
+ (requested_attributes.nil? or requested_attributes.include?('*'))
66
70
  options[:connection].search(search_options) do |dn, attrs|
67
71
  attributes = {}
68
72
  attrs.each do |key, _value|
69
- normalized_attr, normalized_value =
70
- normalize_attribute_options(key, _value)
71
- attributes[normalized_attr] ||= []
72
- attributes[normalized_attr].concat(normalized_value)
73
+ if requested_all_attributes_p or requested_attributes.include?(key)
74
+ normalized_attribute, normalized_value =
75
+ normalize_attribute_options(key, _value)
76
+ attributes[normalized_attribute] ||= []
77
+ attributes[normalized_attribute].concat(normalized_value)
78
+ else
79
+ next
80
+ end
73
81
  end
74
82
  values << [dn, attributes]
75
83
  end
@@ -280,8 +288,9 @@ module ActiveLdap
280
288
  sort_by = options.delete(:sort_by) || self.sort_by
281
289
  order = options.delete(:order) || self.order
282
290
  limit = options.delete(:limit) if sort_by or order
283
- options[:attributes] |= ["objectClass"] if options[:attributes]
284
-
291
+ offset = options.delete(:offset) || offset
292
+ options[:attributes] = options.delete(:attributes) || ['*']
293
+ options[:attributes] |= ['objectClass']
285
294
  results = search(options).collect do |dn, attrs|
286
295
  instantiate([dn, attrs, {:connection => options[:connection]}])
287
296
  end
@@ -295,6 +304,7 @@ module ActiveLdap
295
304
  end
296
305
 
297
306
  results.reverse! if normalize_sort_order(order || "ascend") == :descend
307
+ results = results[offset, results.size] if offset
298
308
  results = results[0, limit] if limit
299
309
  results
300
310
  end
@@ -479,13 +489,6 @@ module ActiveLdap
479
489
  end
480
490
 
481
491
  module Delete
482
- def destroy(targets, options={})
483
- targets = [targets] unless targets.is_a?(Array)
484
- targets.each do |target|
485
- find(target, options).destroy
486
- end
487
- end
488
-
489
492
  def destroy_all(options_or_filter=nil, deprecated_options=nil)
490
493
  if deprecated_options.nil?
491
494
  if options_or_filter.is_a?(String)
@@ -504,24 +507,6 @@ module ActiveLdap
504
507
  end
505
508
  end
506
509
 
507
- def delete(targets, options={})
508
- targets = [targets] unless targets.is_a?(Array)
509
- targets = targets.collect do |target|
510
- ensure_dn_attribute(ensure_base(target))
511
- end
512
- delete_entry(targets, options)
513
- end
514
-
515
- def delete_entry(dn, options={})
516
- options[:connection] ||= connection
517
- begin
518
- options[:connection].delete(dn, options)
519
- rescue Error
520
- format = _("Failed to delete LDAP entry: <%s>: %s")
521
- raise DeleteError.new(format % [dn.inspect, $!.message])
522
- end
523
- end
524
-
525
510
  def delete_all(options_or_filter=nil, deprecated_options=nil)
526
511
  if deprecated_options.nil?
527
512
  if options_or_filter.is_a?(String)
@@ -540,6 +525,33 @@ module ActiveLdap
540
525
 
541
526
  delete_entry(targets, options)
542
527
  end
528
+
529
+ def delete_entry(dn, options={})
530
+ options[:connection] ||= connection
531
+ begin
532
+ options[:connection].delete(dn, options)
533
+ rescue Error
534
+ format = _("Failed to delete LDAP entry: <%s>: %s")
535
+ raise DeleteError.new(format % [dn.inspect, $!.message])
536
+ end
537
+ end
538
+ end
539
+
540
+ module ClassOnlyDelete
541
+ def destroy(targets, options={})
542
+ targets = [targets] unless targets.is_a?(Array)
543
+ targets.each do |target|
544
+ find(target, options).destroy
545
+ end
546
+ end
547
+
548
+ def delete(targets, options={})
549
+ targets = [targets] unless targets.is_a?(Array)
550
+ targets = targets.collect do |target|
551
+ ensure_dn_attribute(ensure_base(target))
552
+ end
553
+ delete_entry(targets, options)
554
+ end
543
555
  end
544
556
 
545
557
  module Update
@@ -566,21 +578,6 @@ module ActiveLdap
566
578
  new_superior, options)
567
579
  end
568
580
 
569
- def update(dn, attributes, options={})
570
- if dn.is_a?(Array)
571
- i = -1
572
- dns = dn
573
- dns.collect do |_dn|
574
- i += 1
575
- update(_dn, attributes[i], options)
576
- end
577
- else
578
- object = find(dn, options)
579
- object.update_attributes(attributes)
580
- object
581
- end
582
- end
583
-
584
581
  def update_all(attributes, filter=nil, options={})
585
582
  search_options = options.dup
586
583
  if filter
@@ -606,5 +603,22 @@ module ActiveLdap
606
603
  end
607
604
  end
608
605
  end
606
+
607
+ module ClassOnlyUpdate
608
+ def update(dn, attributes, options={})
609
+ if dn.is_a?(Array)
610
+ i = -1
611
+ dns = dn
612
+ dns.collect do |_dn|
613
+ i += 1
614
+ update(_dn, attributes[i], options)
615
+ end
616
+ else
617
+ object = find(dn, options)
618
+ object.update_attributes(attributes)
619
+ object
620
+ end
621
+ end
622
+ end
609
623
  end
610
624
  end
@@ -72,5 +72,22 @@ module ActiveLdap
72
72
  true
73
73
  end
74
74
  end
75
+
76
+ def reload
77
+ clear_association_cache
78
+ _, attributes = search(:value => id).find do |_dn, _attributes|
79
+ dn == _dn
80
+ end
81
+ if attributes.nil?
82
+ raise EntryNotFound, _("Can't find DN '%s' to reload") % dn
83
+ end
84
+
85
+ @ldap_data.update(attributes)
86
+ classes, attributes = extract_object_class(attributes)
87
+ self.classes = classes
88
+ self.attributes = attributes
89
+ @new_entry = false
90
+ self
91
+ end
75
92
  end # Persistence
76
93
  end # ActiveLdap
@@ -1,6 +1,9 @@
1
+ require "locale"
1
2
  require 'active_ldap'
2
3
  require 'rails'
3
4
 
5
+ Locale.init(:driver => :cgi)
6
+
4
7
  module ActiveLdap
5
8
  class Railtie < Rails::Railtie
6
9
  config.app_generators.orm :active_ldap
@@ -12,6 +12,7 @@ module ActiveLdap
12
12
  def ids(group)
13
13
  ensure_parse(group)
14
14
  info, ids, aliases = ensure_schema_info(group)
15
+ _ = info = aliases # for suppress a warning on Ruby 1.9.3
15
16
  ids.keys
16
17
  end
17
18
 
@@ -54,6 +55,7 @@ module ActiveLdap
54
55
 
55
56
  # Initialize anything that is required
56
57
  info, ids, aliases = ensure_schema_info(group)
58
+ _ = info # for suppress a warning on Ruby 1.9.3
57
59
  id, name = determine_id_or_name(id_or_name, aliases)
58
60
 
59
61
  # Check already parsed options first
@@ -180,10 +180,10 @@ module ActiveLdap
180
180
  return value if value.nil? or value.is_a?(Time)
181
181
  match_data = FORMAT.match(value)
182
182
  if match_data
183
- required_components = match_data.to_a[1, 6]
183
+ required_components = match_data.to_a[1, 5]
184
184
  return value if required_components.any?(&:nil?)
185
- year, month, day, hour, minute, second =
186
- required_components.collect(&:to_i)
185
+ year, month, day, hour, minute = required_components.collect(&:to_i)
186
+ second = match_data[-3].to_i
187
187
  fraction = match_data[-2]
188
188
  fraction = fraction.to_f if fraction
189
189
  time_zone = match_data[-1]
@@ -224,11 +224,11 @@ module ActiveLdap
224
224
  def validate_normalized_value(value, original_value)
225
225
  match_data = FORMAT.match(value)
226
226
  if match_data
227
- year, month, day, hour, minute, second, fraction, time_zone =
228
- match_data.to_a[1..-1]
227
+ date_data = match_data.to_a[1..-1]
229
228
  missing_components = []
230
- %w(year month day hour minute second).each do |component|
231
- missing_components << component unless eval(component)
229
+ required_components = %w(year month day hour minute)
230
+ required_components.each_with_index do |component, i|
231
+ missing_components << component unless date_data[i]
232
232
  end
233
233
  if missing_components.empty?
234
234
  nil
@@ -41,11 +41,11 @@ module ActiveLdap
41
41
  end
42
42
 
43
43
  def save(*)
44
- valid? ? super: false
44
+ valid? ? super : false
45
45
  end
46
46
 
47
47
  def save!(*)
48
- valid? ? super: raise(EntryInvalid.new(self))
48
+ valid? ? super : raise(EntryInvalid.new(self))
49
49
  end
50
50
 
51
51
  private
@@ -0,0 +1,3 @@
1
+ module ActiveLdap
2
+ VERSION = "3.2.0"
3
+ end
@@ -6,7 +6,7 @@ require 'active_ldap/ldif'
6
6
  module ActiveLdap
7
7
  class Xml
8
8
  class Serializer
9
- PRINTABLE_STRING = /[\x20-\x7e\w\s]*/
9
+ PRINTABLE_STRING = /[\x20-\x7e\t\r\n]*/n
10
10
 
11
11
  def initialize(dn, attributes, schema, options={})
12
12
  @dn = dn
@@ -23,6 +23,7 @@ module ActiveLdap
23
23
  target_attributes.each do |key, values|
24
24
  values = normalize_values(values).sort_by {|value, _| value}
25
25
  if @schema.attribute(key).single_value?
26
+ next if values.empty?
26
27
  serialize_attribute_value(xml, key, *values[0])
27
28
  else
28
29
  serialize_attribute_values(xml, key, values)
@@ -34,13 +35,29 @@ module ActiveLdap
34
35
  private
35
36
  def target_attributes
36
37
  except_dn = false
37
- attributes = @attributes.dup
38
- (@options[:except] || []).each do |name|
39
- if name == "dn"
40
- except_dn = true
41
- else
42
- attributes.delete(name)
38
+ only = @options[:only] || []
39
+ except = @options[:except] || []
40
+ if !only.empty?
41
+ attributes = []
42
+ except_dn = true
43
+ only.each do |name|
44
+ if name == "dn"
45
+ except_dn = false
46
+ elsif @attributes.has_key?(name)
47
+ attributes << [name, @attributes[name]]
48
+ end
43
49
  end
50
+ elsif !except.empty?
51
+ attributes = @attributes.dup
52
+ except.each do |name|
53
+ if name == "dn"
54
+ except_dn = true
55
+ else
56
+ attributes.delete(name)
57
+ end
58
+ end
59
+ else
60
+ attributes = @attributes.dup
44
61
  end
45
62
  attributes = attributes.sort_by {|key, values| key}
46
63
  attributes.unshift(["dn", [@dn]]) unless except_dn
@@ -33,10 +33,10 @@ module ActiveLdap
33
33
 
34
34
  def ldap_mapping(indent=' ')
35
35
  mapping = "ldap_mapping "
36
- mapping_options = [":dn_attribute => #{options[:dn_attribute].dump}"]
37
- mapping_options << ":prefix => #{prefix.dump}"
36
+ mapping_options = [key_value(:dn_attribute, options[:dn_attribute].dump)]
37
+ mapping_options << key_value(:prefix, prefix.dump)
38
38
  if options[:classes]
39
- mapping_options << ":classes => #{options[:classes].inspect}"
39
+ mapping_options << key_value(:classes, options[:classes].inspect)
40
40
  end
41
41
  mapping_options = mapping_options.join(",\n#{indent}#{' ' * mapping.size}")
42
42
  "#{indent}#{mapping}#{mapping_options}"
@@ -0,0 +1,10 @@
1
+ # Your LDAP server need to accept 'phonetic' attribute option for test.
2
+ # This is a LDIF file for OpenLDAP to do the confiugration.
3
+ # You can use this file by the following command linne on Debian GNU/Linux
4
+ # or Ubuntu:
5
+ # % sudo -H ldapmodify -Y EXTERNAL -H ldapi:/// -f test/add-phonetic-attribute-options-to-slapd.ldif
6
+ version: 1
7
+ dn: cn=config
8
+ changetype: modify
9
+ add: olcAttributeOptions
10
+ olcAttributeOptions: phonetic lang-
@@ -0,0 +1,428 @@
1
+ require 'test-unit'
2
+
3
+ require 'erb'
4
+ require 'yaml'
5
+ require 'socket'
6
+ require 'rbconfig'
7
+ require 'tempfile'
8
+
9
+ require 'active_ldap'
10
+
11
+ require File.join(File.expand_path(File.dirname(__FILE__)), "command")
12
+
13
+ LDAP_ENV = "test" unless defined?(LDAP_ENV)
14
+
15
+ module AlTestUtils
16
+ def self.included(base)
17
+ base.class_eval do
18
+ include ActiveLdap::GetTextSupport
19
+ include Utilities
20
+ include Config
21
+ include Connection
22
+ include Populate
23
+ include TemporaryEntry
24
+ include CommandSupport
25
+ include MockLogger
26
+ end
27
+ end
28
+
29
+ module Utilities
30
+ def dn(string)
31
+ ActiveLdap::DN.parse(string)
32
+ end
33
+ end
34
+
35
+ module Config
36
+ def setup
37
+ super
38
+ @base_dir = File.expand_path(File.dirname(__FILE__))
39
+ @top_dir = File.expand_path(File.join(@base_dir, ".."))
40
+ @example_dir = File.join(@top_dir, "examples")
41
+ @fixtures_dir = File.join(@base_dir, "fixtures")
42
+ @config_file = File.join(@base_dir, "config.yaml")
43
+ ActiveLdap::Base.configurations = read_config
44
+ end
45
+
46
+ def teardown
47
+ super
48
+ end
49
+
50
+ def current_configuration
51
+ ActiveLdap::Base.configurations[LDAP_ENV]
52
+ end
53
+
54
+ def read_config
55
+ unless File.exist?(@config_file)
56
+ raise "config file for testing doesn't exist: #{@config_file}"
57
+ end
58
+ erb = ERB.new(File.read(@config_file))
59
+ erb.filename = @config_file
60
+ config = YAML.load(erb.result)
61
+ _adapter = adapter
62
+ config.each do |key, value|
63
+ value["adapter"] = _adapter if _adapter
64
+ end
65
+ config
66
+ end
67
+
68
+ def adapter
69
+ ENV["ACTIVE_LDAP_TEST_ADAPTER"]
70
+ end
71
+
72
+ def fixture(*components)
73
+ File.join(@fixtures_dir, *components)
74
+ end
75
+ end
76
+
77
+ module ExampleFile
78
+ def certificate_path
79
+ File.join(@example_dir, 'example.der')
80
+ end
81
+
82
+ @@certificate = nil
83
+ def certificate
84
+ return @@certificate if @@certificate
85
+ if File.exists?(certificate_path)
86
+ @@certificate = read_binary_file(certificate_path)
87
+ return @@certificate
88
+ end
89
+
90
+ require 'openssl'
91
+ rsa = OpenSSL::PKey::RSA.new(512)
92
+ comment = "Generated by Ruby/OpenSSL"
93
+
94
+ cert = OpenSSL::X509::Certificate.new
95
+ cert.version = 3
96
+ cert.serial = 0
97
+ subject = [["OU", "test"],
98
+ ["CN", Socket.gethostname]]
99
+ name = OpenSSL::X509::Name.new(subject)
100
+ cert.subject = name
101
+ cert.issuer = name
102
+ cert.not_before = Time.now
103
+ cert.not_after = Time.now + (365*24*60*60)
104
+ cert.public_key = rsa.public_key
105
+
106
+ ef = OpenSSL::X509::ExtensionFactory.new(nil, cert)
107
+ ef.issuer_certificate = cert
108
+ cert.extensions = [
109
+ ef.create_extension("basicConstraints","CA:FALSE"),
110
+ ef.create_extension("keyUsage", "keyEncipherment"),
111
+ ef.create_extension("subjectKeyIdentifier", "hash"),
112
+ ef.create_extension("extendedKeyUsage", "serverAuth"),
113
+ ef.create_extension("nsComment", comment),
114
+ ]
115
+ aki = ef.create_extension("authorityKeyIdentifier",
116
+ "keyid:always,issuer:always")
117
+ cert.add_extension(aki)
118
+ cert.sign(rsa, OpenSSL::Digest::SHA1.new)
119
+
120
+ @@certificate = cert.to_der
121
+ @@certificate
122
+ end
123
+
124
+ def jpeg_photo_path
125
+ File.join(@example_dir, 'example.jpg')
126
+ end
127
+
128
+ def jpeg_photo
129
+ read_binary_file(jpeg_photo_path)
130
+ end
131
+
132
+ def read_binary_file(path)
133
+ File.open(path, "rb") do |input|
134
+ input.set_encoding("ascii-8bit") if input.respond_to?(:set_encoding)
135
+ input.read
136
+ end
137
+ end
138
+ end
139
+
140
+ module Connection
141
+ def setup
142
+ super
143
+ ActiveLdap::Base.setup_connection
144
+ end
145
+
146
+ def teardown
147
+ ActiveLdap::Base.remove_active_connections!
148
+ super
149
+ end
150
+ end
151
+
152
+ module Populate
153
+ def setup
154
+ @dumped_data = nil
155
+ super
156
+ begin
157
+ @dumped_data = ActiveLdap::Base.dump(:scope => :sub)
158
+ rescue ActiveLdap::ConnectionError
159
+ end
160
+ ActiveLdap::Base.delete_all(nil, :scope => :sub)
161
+ populate
162
+ end
163
+
164
+ def teardown
165
+ if @dumped_data
166
+ ActiveLdap::Base.setup_connection
167
+ ActiveLdap::Base.delete_all(nil, :scope => :sub)
168
+ ActiveLdap::Base.load(@dumped_data)
169
+ end
170
+ super
171
+ end
172
+
173
+ def populate
174
+ populate_base
175
+ populate_ou
176
+ populate_user_class
177
+ populate_group_class
178
+ populate_associations
179
+ end
180
+
181
+ def populate_base
182
+ ActiveLdap::Populate.ensure_base
183
+ end
184
+
185
+ def ou_class(prefix="")
186
+ ou_class = Class.new(ActiveLdap::Base)
187
+ ou_class.ldap_mapping(:dn_attribute => "ou",
188
+ :prefix => prefix,
189
+ :classes => ["top", "organizationalUnit"])
190
+ ou_class
191
+ end
192
+
193
+ def dc_class(prefix="")
194
+ dc_class = Class.new(ActiveLdap::Base)
195
+ dc_class.ldap_mapping(:dn_attribute => "dc",
196
+ :prefix => prefix,
197
+ :classes => ["top", "dcObject", "organization"])
198
+ dc_class
199
+ end
200
+
201
+ def entry_class(prefix="")
202
+ entry_class = Class.new(ActiveLdap::Base)
203
+ entry_class.ldap_mapping(:prefix => prefix,
204
+ :scope => :sub,
205
+ :classes => ["top"])
206
+ entry_class.dn_attribute = nil
207
+ entry_class
208
+ end
209
+
210
+ def populate_ou
211
+ %w(Users Groups).each do |name|
212
+ make_ou(name)
213
+ end
214
+ end
215
+
216
+ def make_ou(name)
217
+ ActiveLdap::Populate.ensure_ou(name)
218
+ end
219
+
220
+ def make_dc(name)
221
+ ActiveLdap::Populate.ensure_dc(name)
222
+ end
223
+
224
+ def populate_user_class
225
+ @user_class = Class.new(ActiveLdap::Base)
226
+ @user_class_classes = ["posixAccount", "person"]
227
+ @user_class.ldap_mapping :dn_attribute => "uid",
228
+ :prefix => "ou=Users",
229
+ :scope => :sub,
230
+ :classes => @user_class_classes
231
+ assign_class_name(@user_class, "User")
232
+ end
233
+
234
+ def populate_group_class
235
+ @group_class = Class.new(ActiveLdap::Base)
236
+ @group_class.ldap_mapping :prefix => "ou=Groups",
237
+ :scope => :sub,
238
+ :classes => ["posixGroup"]
239
+ assign_class_name(@group_class, "Group")
240
+ end
241
+
242
+ def populate_associations
243
+ @user_class.belongs_to :groups, :many => "memberUid"
244
+ @user_class.belongs_to :primary_group,
245
+ :foreign_key => "gidNumber",
246
+ :primary_key => "gidNumber"
247
+ @group_class.has_many :members, :wrap => "memberUid"
248
+ @group_class.has_many :primary_members,
249
+ :foreign_key => "gidNumber",
250
+ :primary_key => "gidNumber"
251
+ @user_class.set_associated_class(:groups, @group_class)
252
+ @user_class.set_associated_class(:primary_group, @group_class)
253
+ @group_class.set_associated_class(:members, @user_class)
254
+ @group_class.set_associated_class(:primary_members, @user_class)
255
+ end
256
+
257
+ def assign_class_name(klass, name)
258
+ singleton_class = class << klass; self; end
259
+ singleton_class.send(:define_method, :name) do
260
+ name
261
+ end
262
+ if Object.const_defined?(klass.name)
263
+ Object.send(:remove_const, klass.name)
264
+ end
265
+ Object.const_set(klass.name, klass)
266
+ end
267
+ end
268
+
269
+ module TemporaryEntry
270
+ include ExampleFile
271
+
272
+ def setup
273
+ super
274
+ @user_index = 0
275
+ @group_index = 0
276
+ end
277
+
278
+ def make_temporary_user(config={})
279
+ @user_index += 1
280
+ uid = config[:uid] || "temp-user#{@user_index}"
281
+ ensure_delete_user(uid) do
282
+ password = config[:password] || "password#{@user_index}"
283
+ uid_number = config[:uid_number] || default_uid
284
+ gid_number = config[:gid_number] || default_gid
285
+ home_directory = config[:home_directory] || "/nonexistent"
286
+ see_also = config[:see_also]
287
+ _wrap_assertion do
288
+ assert(!@user_class.exists?(uid))
289
+ assert_raise(ActiveLdap::EntryNotFound) do
290
+ @user_class.find(uid).dn
291
+ end
292
+ user = @user_class.new(uid)
293
+ assert(user.new_entry?)
294
+ user.cn = user.uid
295
+ user.sn = user.uid
296
+ user.uid_number = uid_number
297
+ user.gid_number = gid_number
298
+ user.home_directory = home_directory
299
+ user.user_password = ActiveLdap::UserPassword.ssha(password)
300
+ user.see_also = see_also
301
+ unless config[:simple]
302
+ user.add_class('shadowAccount', 'inetOrgPerson',
303
+ 'organizationalPerson')
304
+ user.user_certificate = certificate
305
+ user.jpeg_photo = jpeg_photo
306
+ end
307
+ user.save
308
+ assert(!user.new_entry?)
309
+ yield(@user_class.find(user.uid), password)
310
+ end
311
+ end
312
+ end
313
+
314
+ def make_temporary_group(config={})
315
+ @group_index += 1
316
+ cn = config[:cn] || "temp-group#{@group_index}"
317
+ ensure_delete_group(cn) do
318
+ gid_number = config[:gid_number] || default_gid
319
+ _wrap_assertion do
320
+ assert(!@group_class.exists?(cn))
321
+ assert_raise(ActiveLdap::EntryNotFound) do
322
+ @group_class.find(cn)
323
+ end
324
+ group = @group_class.new(cn)
325
+ assert(group.new_entry?)
326
+ group.gid_number = gid_number
327
+ assert(group.save)
328
+ assert(!group.new_entry?)
329
+ yield(@group_class.find(group.cn))
330
+ end
331
+ end
332
+ end
333
+
334
+ def ensure_delete_user(uid)
335
+ yield(uid)
336
+ ensure
337
+ if @user_class.exists?(uid)
338
+ @user_class.search(:value => uid) do |dn, attribute|
339
+ @user_class.remove_connection(dn)
340
+ @user_class.delete(dn)
341
+ end
342
+ end
343
+ end
344
+
345
+ def ensure_delete_group(cn)
346
+ yield(cn)
347
+ ensure
348
+ @group_class.delete(cn) if @group_class.exists?(cn)
349
+ end
350
+
351
+ def default_uid
352
+ "10000#{@user_index}"
353
+ end
354
+
355
+ def default_gid
356
+ "10000#{@group_index}"
357
+ end
358
+ end
359
+
360
+ module CommandSupport
361
+ def setup
362
+ super
363
+ @fakeroot = "fakeroot"
364
+ @ruby = File.join(::RbConfig::CONFIG["bindir"],
365
+ ::RbConfig::CONFIG["RUBY_INSTALL_NAME"])
366
+ @top_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
367
+ @examples_dir = File.join(@top_dir, "examples")
368
+ @lib_dir = File.join(@top_dir, "lib")
369
+ @ruby_args = [
370
+ "-I", @examples_dir,
371
+ "-I", @lib_dir,
372
+ ]
373
+ end
374
+
375
+ def run_command(*args, &block)
376
+ file = Tempfile.new("al-command-support")
377
+ file.open
378
+ file.puts(ActiveLdap::Base.configurations["test"].to_yaml)
379
+ file.close
380
+ run_ruby(*[@command, "--config", file.path, *args], &block)
381
+ end
382
+
383
+ def run_ruby(*ruby_args, &block)
384
+ args = [@ruby, *@ruby_args]
385
+ args.concat(ruby_args)
386
+ Command.run(*args, &block)
387
+ end
388
+
389
+ def run_ruby_with_fakeroot(*ruby_args, &block)
390
+ args = [@fakeroot, @ruby, *@ruby_args]
391
+ args.concat(ruby_args)
392
+ Command.run(*args, &block)
393
+ end
394
+ end
395
+
396
+ module MockLogger
397
+ def make_mock_logger
398
+ logger = Object.new
399
+ class << logger
400
+ def messages(type)
401
+ @messages ||= {}
402
+ @messages[type] ||= []
403
+ @messages[type]
404
+ end
405
+
406
+ def info(content=nil)
407
+ messages(:info) << (block_given? ? yield : content)
408
+ end
409
+ def warn(content=nil)
410
+ messages(:warn) << (block_given? ? yield : content)
411
+ end
412
+ def error(content=nil)
413
+ messages(:error) << (block_given? ? yield : content)
414
+ end
415
+ end
416
+ logger
417
+ end
418
+
419
+ def with_mock_logger
420
+ original_logger = ActiveLdap::Base.logger
421
+ mock_logger = make_mock_logger
422
+ ActiveLdap::Base.logger = mock_logger
423
+ yield(mock_logger)
424
+ ensure
425
+ ActiveLdap::Base.logger = original_logger
426
+ end
427
+ end
428
+ end