activeldap 3.1.1 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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