activeldap 1.0.9 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/CHANGES +648 -567
  2. data/README +53 -48
  3. data/Rakefile +25 -53
  4. data/TODO +2 -0
  5. data/data/locale/en/LC_MESSAGES/active-ldap.mo +0 -0
  6. data/data/locale/ja/LC_MESSAGES/active-ldap.mo +0 -0
  7. data/examples/al-admin/app/controllers/application_controller.rb +1 -1
  8. data/examples/al-admin/app/views/_entry/_attributes_information.html.erb +7 -1
  9. data/examples/al-admin/app/views/users/_attributes_update_form.html.erb +13 -1
  10. data/examples/al-admin/config/environment.rb +2 -3
  11. data/lib/active_ldap.rb +103 -98
  12. data/lib/active_ldap/association/belongs_to_many.rb +7 -7
  13. data/lib/active_ldap/association/has_many.rb +4 -4
  14. data/lib/active_ldap/associations.rb +29 -5
  15. data/lib/active_ldap/attributes.rb +5 -1
  16. data/lib/active_ldap/base.rb +17 -13
  17. data/lib/active_ldap/configuration.rb +3 -4
  18. data/lib/active_ldap/connection.rb +3 -3
  19. data/lib/active_ldap/get_text/parser.rb +4 -2
  20. data/lib/active_ldap/helper.rb +59 -0
  21. data/lib/active_ldap/operations.rb +15 -10
  22. data/lib/active_ldap/xml.rb +22 -30
  23. data/po/en/active-ldap.po +221 -154
  24. data/po/ja/active-ldap.po +237 -178
  25. data/test-unit/History.txt +26 -0
  26. data/test-unit/Manifest.txt +1 -1
  27. data/test-unit/README.txt +1 -0
  28. data/test-unit/Rakefile +6 -1
  29. data/test-unit/lib/test/unit/autorunner.rb +6 -0
  30. data/test-unit/lib/test/unit/testcase.rb +101 -36
  31. data/test-unit/test/{test_testcase.rb → test-testcase.rb} +30 -1
  32. data/test-unit/test/test_assertions.rb +1 -1
  33. data/test/al-test-utils.rb +3 -1
  34. data/test/test_associations.rb +75 -6
  35. data/test/test_base.rb +45 -3
  36. metadata +75 -45
  37. data/examples/al-admin/config/initializers/gettext.rb +0 -15
@@ -6,11 +6,11 @@ module ActiveLdap
6
6
  private
7
7
  def insert_entry(entry)
8
8
  old_value = entry[@options[:many], true]
9
- foreign_key_name = @options[:foreign_key_name]
10
- if foreign_key_name == "dn"
9
+ primary_key_name = @options[:primary_key_name]
10
+ if primary_key_name == "dn"
11
11
  old_value = dn_values_to_string_values(old_value)
12
12
  end
13
- new_value = old_value + @owner[foreign_key_name, true]
13
+ new_value = old_value + @owner[primary_key_name, true]
14
14
  new_value = new_value.uniq.sort
15
15
  if old_value != new_value
16
16
  entry[@options[:many]] = new_value
@@ -21,11 +21,11 @@ module ActiveLdap
21
21
  def delete_entries(entries)
22
22
  entries.each do |entry|
23
23
  old_value = entry[@options[:many], true]
24
- foreign_key_name = @options[:foreign_key_name]
25
- if foreign_key_name == "dn"
24
+ primary_key_name = @options[:primary_key_name]
25
+ if primary_key_name == "dn"
26
26
  old_value = dn_values_to_string_values(old_value)
27
27
  end
28
- new_value = old_value - @owner[foreign_key_name, true]
28
+ new_value = old_value - @owner[primary_key_name, true]
29
29
  new_value = new_value.uniq.sort
30
30
  if old_value != new_value
31
31
  entry[@options[:many]] = new_value
@@ -35,7 +35,7 @@ module ActiveLdap
35
35
  end
36
36
 
37
37
  def find_target
38
- values = @owner[@options[:foreign_key_name], true].compact
38
+ values = @owner[@options[:primary_key_name], true].compact
39
39
  return [] if values.empty?
40
40
 
41
41
  key = @options[:many]
@@ -8,17 +8,17 @@ module ActiveLdap
8
8
 
9
9
  private
10
10
  def insert_entry(entry)
11
- entry[primary_key] = @owner[@options[:foreign_key_name]]
11
+ entry[@options[:foreign_key_name]] = @owner[primary_key]
12
12
  entry.save
13
13
  end
14
14
 
15
15
  def find_target
16
- collect_targets(:foreign_key_name)
16
+ collect_targets(:primary_key_name)
17
17
  end
18
18
 
19
19
  def delete_entries(entries)
20
- key = primary_key
21
- components = @owner[@options[:foreign_key_name], true].reject do |value|
20
+ key = @options[:foreign_key_name]
21
+ components = @owner[primary_key, true].reject do |value|
22
22
  value.nil?
23
23
  end
24
24
  filter = [:and,
@@ -37,7 +37,9 @@ module ActiveLdap
37
37
  # Example:
38
38
  # belongs_to :groups, :class_name => "Group",
39
39
  # :many => "memberUid" # Group#memberUid
40
- # # :foreign_key => "uid" # User#uid
40
+ # # :primary_key => "uid" # User#uid
41
+ # ## deprecated since 1.1.0. Use :primary_key instead.
42
+ # ## :foreign_key => "uid" # User#uid
41
43
  # # dn attribute value is used by default
42
44
  # belongs_to :primary_group, :class_name => "Group",
43
45
  # :foreign_key => "gidNumber", # User#gidNumber
@@ -61,7 +63,14 @@ module ActiveLdap
61
63
  }
62
64
  if opts[:many]
63
65
  association_class = Association::BelongsToMany
64
- opts[:foreign_key_name] ||= dn_attribute
66
+ foreign_key_name = opts[:foreign_key_name]
67
+ if foreign_key_name
68
+ message = _(":foreign_key belongs_to(:many) option is " \
69
+ "deprecated since 1.1.0. Use :primary_key instead.")
70
+ ActiveSupport::Deprecation.warn(message)
71
+ opts[:primary_key_name] ||= foreign_key_name
72
+ end
73
+ opts[:primary_key_name] ||= dn_attribute
65
74
  else
66
75
  association_class = Association::BelongsTo
67
76
  opts[:foreign_key_name] ||= "#{association_id}_id"
@@ -92,15 +101,19 @@ module ActiveLdap
92
101
  #
93
102
  # Example:
94
103
  # has_many :primary_members, :class_name => "User",
95
- # :primary_key => "gidNumber", # User#gidNumber
96
- # :foreign_key => "gidNumber" # Group#gidNumber
104
+ # :primary_key => "gidNumber", # Group#gidNumber
105
+ # :foreign_key => "gidNumber" # User#gidNumber
106
+ # ## deprecated since 1.1.0. Those options
107
+ # ## are inverted.
108
+ # # :primary_key => "gidNumber", # User#gidNumber
109
+ # # :foreign_key => "gidNumber" # Group#gidNumber
97
110
  # has_many :members, :class_name => "User",
98
111
  # :wrap => "memberUid" # Group#memberUid
99
112
  def has_many(association_id, options = {})
100
113
  validate_has_many_options(options)
101
114
  klass = options[:class]
102
115
  klass ||= (options[:class_name] || association_id.to_s).classify
103
- foreign_key = options[:foreign_key] || "#{association_id}_id"
116
+ foreign_key = options[:foreign_key]
104
117
  primary_key = options[:primary_key]
105
118
  set_associated_class(association_id, klass)
106
119
 
@@ -112,9 +125,20 @@ module ActiveLdap
112
125
  :extend => options[:extend],
113
126
  }
114
127
  if opts[:wrap]
128
+ opts[:foreign_key_name] ||= "#{association_id}_id"
115
129
  association_class = Association::HasManyWrap
116
130
  else
117
131
  association_class = Association::HasMany
132
+ primary_key_name = opts[:primary_key_name]
133
+ foreign_key_name = opts[:foreign_key_name]
134
+ if primary_key_name != foreign_key_name and
135
+ !new.have_attribute?(primary_key_name)
136
+ message = _(":primary_key and :foreign_key has_many options are " \
137
+ "inverted their mean since 1.1.0. Please invert them.")
138
+ ActiveSupport::Deprecation.warn(message)
139
+ opts[:foreign_key_name] = primary_key_name
140
+ opts[:primary_key_name] = foreign_key_name
141
+ end
118
142
  end
119
143
 
120
144
  association_accessor(association_id) do |target|
@@ -40,8 +40,11 @@ module ActiveLdap
40
40
  when Hash
41
41
  result = {}
42
42
  value.each do |k, v|
43
- result[k] = remove_blank_value(v) || []
43
+ v = remove_blank_value(v)
44
+ next if v.nil?
45
+ result[k] = v
44
46
  end
47
+ result = nil if result.blank?
45
48
  result
46
49
  when Array
47
50
  result = []
@@ -50,6 +53,7 @@ module ActiveLdap
50
53
  next if v.nil?
51
54
  result << v
52
55
  end
56
+ result = nil if result.blank?
53
57
  result
54
58
  when String
55
59
  if /\A\s*\z/ =~ value
@@ -678,7 +678,17 @@ module ActiveLdap
678
678
  # [ User.find("a"), User.find("b"), User.find("c") ] &
679
679
  # [ User.find("a"), User.find("d") ] # => [ User.find("a") ]
680
680
  def hash
681
- dn.hash
681
+ return super if @_hashing # workaround for GetText :<
682
+ _dn = nil
683
+ begin
684
+ @_hashing = true
685
+ _dn = dn
686
+ rescue DistinguishedNameInvalid, DistinguishedNameNotSetError
687
+ return super
688
+ ensure
689
+ @_hashing = false
690
+ end
691
+ _dn.hash
682
692
  end
683
693
 
684
694
  def may
@@ -897,6 +907,7 @@ module ActiveLdap
897
907
  def to_xml(options={})
898
908
  options = options.dup
899
909
  options[:root] ||= (self.class.name || '').underscore
910
+ options[:root] = 'anonymous' if options[:root].blank?
900
911
  except = options[:except]
901
912
  if except
902
913
  options[:except] = except.collect do |name|
@@ -1151,6 +1162,7 @@ module ActiveLdap
1151
1162
  @dn_is_base = false
1152
1163
  @dn_split_value = nil
1153
1164
  @connection ||= nil
1165
+ @_hashing = false
1154
1166
  clear_connection_based_cache
1155
1167
  end
1156
1168
 
@@ -1322,7 +1334,7 @@ module ActiveLdap
1322
1334
  ensure_update_dn
1323
1335
  dn_value = id
1324
1336
  if dn_value.nil?
1325
- format =_("%s's DN attribute (%s) isn't set")
1337
+ format = _("%s's DN attribute (%s) isn't set")
1326
1338
  message = format % [self.inspect, dn_attribute]
1327
1339
  raise DistinguishedNameNotSetError.new, message
1328
1340
  end
@@ -1394,17 +1406,9 @@ module ActiveLdap
1394
1406
  value = self.class.remove_blank_value(value) || []
1395
1407
  next if v == value
1396
1408
 
1397
- # Create mod entries
1398
- if self.class.blank_value?(value)
1399
- # Since some types do not have equality matching rules,
1400
- # delete doesn't work
1401
- # Replacing with nothing is equivalent.
1402
- if !data.has_key?(k) and schema.attribute(k).binary_required?
1403
- value = [{'binary' => []}]
1404
- end
1405
- else
1406
- # Ditched delete then replace because attribs with no equality
1407
- # match rules will fails
1409
+ if self.class.blank_value?(value) and
1410
+ schema.attribute(k).binary_required?
1411
+ value = [{'binary' => []}]
1408
1412
  end
1409
1413
  attributes.push([:replace, k, value])
1410
1414
  end
@@ -107,10 +107,9 @@ module ActiveLdap
107
107
  target.base = value.gsub(/['}{#]/, '')
108
108
  when :scope, :ldap_scope
109
109
  if key == :ldap_scope
110
- logger.warning do
111
- _(":ldap_scope configuration option is deprecated. " \
112
- "Use :scope instead.")
113
- end
110
+ message = _(":ldap_scope configuration option is deprecated. " \
111
+ "Use :scope instead.")
112
+ ActiveSupport::Deprecation.warn(message)
114
113
  end
115
114
  target.scope = value
116
115
  configuration[:scope] = value
@@ -95,9 +95,9 @@ module ActiveLdap
95
95
  raise AdapterNotFound.new(adapter)
96
96
  end
97
97
  if config.has_key?(:ldap_scope)
98
- logger.warning do
99
- _(":ldap_scope connection option is deprecated. Use :scope instead.")
100
- end
98
+ message = _(":ldap_scope connection option is deprecated. " \
99
+ "Use :scope instead.")
100
+ ActiveSupport::Deprecation.warn(message)
101
101
  config[:scope] ||= config.delete(:ldap_scope)
102
102
  end
103
103
  config = remove_connection_related_configuration(config)
@@ -11,7 +11,7 @@ module ActiveLdap
11
11
  configuration = default_configuration.merge(configuration)
12
12
 
13
13
  configuration = extract_options(configuration)
14
- ActiveLdap::Base.establish_connection(configuration)
14
+ ActiveLdap::Base.setup_connection(configuration)
15
15
  end
16
16
 
17
17
  def parse(file, targets=[])
@@ -72,7 +72,9 @@ module ActiveLdap
72
72
  if File.exists?(configuration)
73
73
  require 'erb'
74
74
  require 'yaml'
75
- configuration = YAML.load(ERB.new(File.read(configuration)).result)
75
+ erb = ERB.new(File.read(configuration))
76
+ erb.filename = configuration
77
+ configuration = YAML.load(erb.result)
76
78
  else
77
79
  ENV["RAILS_ENV"] = configuration
78
80
  require 'config/environment'
@@ -29,5 +29,64 @@ module ActiveLdap
29
29
  Base.human_syntax_description(syntax)
30
30
  end
31
31
  alias_method(:lsd_, :ldap_syntax_description_gettext)
32
+
33
+ def ldap_field(type, object_name, method, options={})
34
+ case type
35
+ when "radio_button", "check_box", "text_area"
36
+ form_method = type
37
+ else
38
+ form_method = "#{type}_field"
39
+ end
40
+
41
+ object = options[:object]
42
+ if object.nil?
43
+ normalized_object_name = object_name.to_s.sub(/\[\](\])?$/, "\\1")
44
+ object = instance_variable_get("@#{normalized_object_name}")
45
+ end
46
+ values = object.nil? ? nil : object[method, true]
47
+ values = [nil] if values.blank?
48
+ required_ldap_options = options.delete(:ldap_options) || []
49
+ required_ldap_options.each do |required_ldap_option|
50
+ found = false
51
+ values.each do |value|
52
+ next unless value.is_a?(Hash)
53
+ if Hash.to_a[0].to_s == required_ldap_option.to_s
54
+ found = true
55
+ break
56
+ end
57
+ end
58
+ values << {required_ldap_option => ""} unless found
59
+ end
60
+
61
+ fields = []
62
+ collect_values = Proc.new do |value, ldap_options|
63
+ case value
64
+ when Hash
65
+ value.each do |k, v|
66
+ collect_values.call(v, ldap_options + [k])
67
+ end
68
+ when Array
69
+ value.each do |v|
70
+ collect_values.call(v, ldap_options)
71
+ end
72
+ else
73
+ id = "#{object_name}_#{method}"
74
+ name = "#{object_name}[#{method}][]"
75
+ ldap_options.collect.each do |ldap_option|
76
+ id << "_#{ldap_option}"
77
+ name << "[#{ldap_option}][]"
78
+ end
79
+ ldap_value_options = {:id => id, :name => name, :value => value}
80
+ field = send(form_method, object_name, method,
81
+ ldap_value_options.merge(options))
82
+ if block_given?
83
+ field = yield(field, {:options => ldap_options, :value => value})
84
+ end
85
+ fields << field unless field.blank?
86
+ end
87
+ end
88
+ collect_values.call(values, [])
89
+ fields.join("\n")
90
+ end
32
91
  end
33
92
  end
@@ -46,9 +46,9 @@ module ActiveLdap
46
46
  _base = options[:base] ? [options[:base]] : [prefix, base]
47
47
  _base = prepare_search_base(_base)
48
48
  if options.has_key?(:ldap_scope)
49
- logger.warning do
50
- _(":ldap_scope search option is deprecated. Use :scope instead.")
51
- end
49
+ message = _(":ldap_scope search option is deprecated. " \
50
+ "Use :scope instead.")
51
+ ActiveSupport::Deprecation.warn(message)
52
52
  options[:scope] ||= options[:ldap_scope]
53
53
  end
54
54
  search_options = {
@@ -497,18 +497,23 @@ module ActiveLdap
497
497
  options[:connection].delete(dn, options)
498
498
  end
499
499
 
500
- def delete_all(filter=nil, options={})
501
- options = {:base => base, :scope => scope}.merge(options)
502
- options = options.merge(:filter => filter) if filter
503
- options[:connection] ||= connection
504
- conn = options[:connection]
505
- targets = conn.search(options).collect do |dn, attributes|
500
+ def delete_all(options_or_filter=nil, deprecated_options=nil)
501
+ if deprecated_options.nil?
502
+ if options_or_filter.is_a?(String)
503
+ options = {:filter => options_or_filter}
504
+ else
505
+ options = (options_or_filter || {}).dup
506
+ end
507
+ else
508
+ options = deprecated_options.merge(:filter => options_or_filter)
509
+ end
510
+ targets = search(options).collect do |dn, attributes|
506
511
  dn
507
512
  end.sort_by do |dn|
508
513
  dn.upcase.reverse
509
514
  end.reverse
510
515
 
511
- conn.delete(targets)
516
+ options[:connection].delete(targets)
512
517
  end
513
518
  end
514
519
 
@@ -1,4 +1,5 @@
1
1
  require 'erb'
2
+ require 'builder'
2
3
 
3
4
  require 'active_ldap/ldif'
4
5
 
@@ -16,17 +17,18 @@ module ActiveLdap
16
17
 
17
18
  def to_s
18
19
  root = @options[:root]
19
- result = "<#{root}>\n"
20
- target_attributes.each do |key, values|
21
- values = normalize_values(values).sort_by {|value, _| value}
22
- if @schema.attribute(key).single_value?
23
- result << " #{serialize_attribute_value(key, *values[0])}\n"
24
- else
25
- result << serialize_attribute_values(key, values)
20
+ indent = @options[:indent] || 2
21
+ xml = @options[:builder] || Builder::XmlMarkup.new(:indent => indent)
22
+ xml.tag!(root) do
23
+ target_attributes.each do |key, values|
24
+ values = normalize_values(values).sort_by {|value, _| value}
25
+ if @schema.attribute(key).single_value?
26
+ serialize_attribute_value(xml, key, *values[0])
27
+ else
28
+ serialize_attribute_values(xml, key, values)
29
+ end
26
30
  end
27
31
  end
28
- result << "</#{root}>\n"
29
- result
30
32
  end
31
33
 
32
34
  private
@@ -77,36 +79,26 @@ module ActiveLdap
77
79
  targets
78
80
  end
79
81
 
80
- def serialize_attribute_values(name, values)
81
- return "" if values.blank?
82
+ def serialize_attribute_values(xml, name, values)
83
+ return if values.blank?
82
84
 
83
- result = ""
84
85
  if name == "dn" or @options[:type].to_s.downcase == "ldif"
85
- values.collect do |value, xml_attributes|
86
- xml = serialize_attribute_value(name, value, xml_attributes)
87
- result << " #{xml}\n"
86
+ values.each do |value, xml_attributes|
87
+ serialize_attribute_value(xml, name, value, xml_attributes)
88
88
  end
89
89
  else
90
90
  plural_name = name.pluralize
91
- result << " <#{plural_name} type=\"array\">\n"
92
- values.each do |value, xml_attributes|
93
- xml = serialize_attribute_value(name, value, xml_attributes)
94
- result << " #{xml}\n"
91
+ attributes = @options[:skip_types] ? {} : {"type" => "array"}
92
+ xml.tag!(plural_name, attributes) do
93
+ values.each do |value, xml_attributes|
94
+ serialize_attribute_value(xml, name, value, xml_attributes)
95
+ end
95
96
  end
96
- result << " </#{plural_name}>\n"
97
97
  end
98
- result
99
98
  end
100
99
 
101
- def serialize_attribute_value(name, value, xml_attributes)
102
- if xml_attributes.blank?
103
- xml_attributes = ""
104
- else
105
- xml_attributes = " " + xml_attributes.collect do |n, v|
106
- "#{ERB::Util.h(n)}=\"#{ERB::Util.h(v)}\""
107
- end.join(" ")
108
- end
109
- "<#{name}#{xml_attributes}>#{ERB::Util.h(value)}</#{name}>"
100
+ def serialize_attribute_value(xml, name, value, xml_attributes)
101
+ xml.tag!(name, value, xml_attributes)
110
102
  end
111
103
  end
112
104