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
@@ -0,0 +1,31 @@
1
+ #
2
+ module ActiveLdap
3
+ module AttributeMethods
4
+ module Query
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ attribute_method_suffix '?'
9
+ end
10
+
11
+ protected
12
+ def get_attribute_as_query(name, force_array=false)
13
+ name, value = get_attribute_before_type_cast(name, force_array)
14
+ if force_array
15
+ value.collect {|x| !false_value?(x)}
16
+ else
17
+ !false_value?(value)
18
+ end
19
+ end
20
+
21
+ def false_value?(value)
22
+ value.nil? or value == false or value == [] or
23
+ value == "false" or value == "FALSE" or value == ""
24
+ end
25
+
26
+ def attribute?(attr)
27
+ return get_attribute_as_query(attr)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,44 @@
1
+ module ActiveLdap
2
+ module AttributeMethods
3
+ module Read
4
+ extend ActiveSupport::Concern
5
+
6
+ protected
7
+ def attribute(attr, *args)
8
+ return get_attribute(attr, args.first)
9
+ end
10
+
11
+ # get_attribute
12
+ #
13
+ # Return the value of the attribute called by method_missing?
14
+ def get_attribute(name, force_array=false)
15
+ name, value = get_attribute_before_type_cast(name, force_array)
16
+ return value if name.nil?
17
+ attribute = schema.attribute(name)
18
+ type_cast(attribute, value)
19
+ end
20
+
21
+ def type_cast(attribute, value)
22
+ case value
23
+ when Hash
24
+ result = {}
25
+ value.each do |option, val|
26
+ result[option] = type_cast(attribute, val)
27
+ end
28
+ if result.size == 1 and result.has_key?("binary")
29
+ result["binary"]
30
+ else
31
+ result
32
+ end
33
+ when Array
34
+ value.collect do |val|
35
+ type_cast(attribute, val)
36
+ end
37
+ else
38
+ attribute.type_cast(value)
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,38 @@
1
+ module ActiveLdap
2
+ module AttributeMethods
3
+ module Write
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ attribute_method_suffix '='
8
+ end
9
+
10
+ protected
11
+ def attribute=(attr, *args)
12
+ return set_attribute(attr, args.first)
13
+ end
14
+
15
+ # set_attribute
16
+ #
17
+ # Set the value of the attribute called by method_missing?
18
+ def set_attribute(name, value)
19
+ real_name = to_real_attribute_name(name)
20
+ _dn_attribute = nil
21
+ valid_dn_attribute = true
22
+ begin
23
+ _dn_attribute = dn_attribute
24
+ rescue DistinguishedNameInvalid
25
+ valid_dn_attribute = false
26
+ end
27
+ if valid_dn_attribute and real_name == _dn_attribute
28
+ real_name, value = register_new_dn_attribute(real_name, value)
29
+ end
30
+ raise UnknownAttribute.new(name) if real_name.nil?
31
+
32
+ @data[real_name] = value
33
+ @simplified_data = nil
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -9,17 +9,6 @@ module ActiveLdap
9
9
  end
10
10
 
11
11
  module ClassMethods
12
- def attr_protected(*attributes)
13
- targets = attributes.collect {|attr| attr.to_s} - protected_attributes
14
- instance_variable_set("@attr_protected", targets)
15
- end
16
-
17
- def protected_attributes
18
- ancestors[0..(ancestors.index(Base))].inject([]) do |result, ancestor|
19
- result + ancestor.instance_eval {@attr_protected ||= []}
20
- end
21
- end
22
-
23
12
  def blank_value?(value)
24
13
  case value
25
14
  when Hash
@@ -149,32 +138,35 @@ module ActiveLdap
149
138
  end
150
139
 
151
140
  private
152
- def remove_attributes_protected_from_mass_assignment(targets)
141
+ def sanitize_for_mass_assignment(attributes, role=nil)
142
+ role ||= :default
143
+ authorizer = mass_assignment_authorizer(role)
144
+ black_list_p =
145
+ authorizer.is_a?(ActiveModel::MassAssignmentSecurity::BlackList)
146
+
147
+ always_needless_attributes = {}
153
148
  needless_attributes = {}
154
- (attributes_protected_by_default +
155
- (self.class.protected_attributes || [])).each do |name|
156
- needless_attributes[to_real_attribute_name(name)] = true
157
- end
158
149
 
159
150
  _dn_attribute = nil
160
151
  begin
161
152
  _dn_attribute = dn_attribute_with_fallback
162
153
  rescue DistinguishedNameInvalid
163
154
  end
164
- targets.collect do |key, value|
155
+ [_dn_attribute, 'objectClass'].compact.each do |name|
156
+ always_needless_attributes[to_real_attribute_name(name)] = true
157
+ end
158
+ authorizer.each do |name|
159
+ needless_attributes[to_real_attribute_name(name)] = black_list_p
160
+ end
161
+
162
+ sanitized_attributes = attributes.collect do |key, value|
165
163
  key = _dn_attribute if ["id", "dn"].include?(key.to_s)
166
164
  [to_real_attribute_name(key) || key, value]
167
- end.reject do |key, value|
168
- needless_attributes[key]
169
165
  end
170
- end
171
-
172
- def attributes_protected_by_default
173
- begin
174
- _dn_attribute = dn_attribute_with_fallback
175
- rescue DistinguishedNameInvalid
166
+ sanitized_attributes = sanitized_attributes.reject do |key, value|
167
+ always_needless_attributes[key] or needless_attributes[key]
176
168
  end
177
- [_dn_attribute, 'objectClass'].compact
169
+ sanitized_attributes
178
170
  end
179
171
 
180
172
  def normalize_attribute_name(name)
@@ -281,6 +281,7 @@ module ActiveLdap
281
281
  # by extension classes.
282
282
  class Base
283
283
  include GetTextSupport
284
+ public :gettext
284
285
  public :_
285
286
 
286
287
  if Object.const_defined?(:Reloadable)
@@ -344,8 +345,9 @@ module ActiveLdap
344
345
  end
345
346
  end
346
347
 
347
- # Connect and bind to LDAP creating a class variable for use by
348
- # all ActiveLdap objects.
348
+ # Set LDAP connection configuration up. It doesn't connect
349
+ # and bind to LDAP server. A connection to LDAP server is
350
+ # created when it's needed.
349
351
  #
350
352
  # == +config+
351
353
  # +config+ must be a hash that may contain any of the following fields:
@@ -793,65 +795,6 @@ module ActiveLdap
793
795
  self.class.default_search_attribute
794
796
  end
795
797
 
796
- # method_missing
797
- #
798
- # If a given method matches an attribute or an attribute alias
799
- # then call the appropriate method.
800
- # TODO: Determine if it would be better to define each allowed method
801
- # using class_eval instead of using method_missing. This would
802
- # give tab completion in irb.
803
- def method_missing(name, *args, &block)
804
- key = name.to_s
805
- case key
806
- when /=$/
807
- real_key = $PREMATCH
808
- if have_attribute?(real_key, ['objectClass'])
809
- if args.size != 1
810
- raise ArgumentError,
811
- _("wrong number of arguments (%d for 1)") % args.size
812
- end
813
- return set_attribute(real_key, *args, &block)
814
- end
815
- when /(?:(_before_type_cast)|(\?))?$/
816
- real_key = $PREMATCH
817
- before_type_cast = !$1.nil?
818
- query = !$2.nil?
819
- if have_attribute?(real_key, ['objectClass'])
820
- if args.size > 1
821
- raise ArgumentError,
822
- _("wrong number of arguments (%d for 1)") % args.size
823
- end
824
- if before_type_cast
825
- return get_attribute_before_type_cast(real_key, *args)[1]
826
- elsif query
827
- return get_attribute_as_query(real_key, *args)
828
- else
829
- return get_attribute(real_key, *args)
830
- end
831
- end
832
- end
833
- super
834
- end
835
-
836
- # Add available attributes to the methods
837
- def methods(inherited_too=true)
838
- target_names = entry_attribute.all_names
839
- target_names -= ['objectClass', 'objectClass'.underscore]
840
- super + target_names.uniq.collect do |x|
841
- [x, "#{x}=", "#{x}?", "#{x}_before_type_cast"]
842
- end.flatten
843
- end
844
-
845
- alias_method :respond_to_without_attributes?, :respond_to?
846
- def respond_to?(name, include_priv=false)
847
- return true if super
848
-
849
- name = name.to_s
850
- return true if have_attribute?(name, ["objectClass"])
851
- return false if /(?:=|\?|_before_type_cast)$/ !~ name
852
- have_attribute?($PREMATCH, ["objectClass"])
853
- end
854
-
855
798
  # Updates a given attribute and saves immediately
856
799
  def update_attribute(name, value)
857
800
  send("#{name}=", value)
@@ -885,8 +828,18 @@ module ActiveLdap
885
828
  # Do not let URL/form hackers supply the keys.
886
829
  def attributes=(new_attributes)
887
830
  return if new_attributes.blank?
831
+ assign_attributes(new_attributes)
832
+ end
833
+
834
+ def assign_attributes(new_attributes, options={})
835
+ return if new_attributes.blank?
836
+
888
837
  _schema = _local_entry_attribute = nil
889
- targets = remove_attributes_protected_from_mass_assignment(new_attributes)
838
+ if options[:without_protection]
839
+ targets = new_attributes
840
+ else
841
+ targets = sanitize_for_mass_assignment(new_attributes, options[:role])
842
+ end
890
843
  targets.each do |key, value|
891
844
  setter = "#{key}="
892
845
  unless respond_to?(setter)
@@ -912,9 +865,10 @@ module ActiveLdap
912
865
  options = options.dup
913
866
  options[:root] ||= (self.class.name || '').underscore
914
867
  options[:root] = 'anonymous' if options[:root].blank?
915
- except = options[:except]
916
- if except
917
- options[:except] = except.collect do |name|
868
+ [:only, :except].each do |attribute_names_key|
869
+ names = options[attribute_names_key]
870
+ next if names.nil?
871
+ options[attribute_names_key] = names.collect do |name|
918
872
  if name.to_s.downcase == "dn"
919
873
  "dn"
920
874
  else
@@ -935,23 +889,6 @@ module ActiveLdap
935
889
  end
936
890
  alias_method :has_attribute?, :have_attribute?
937
891
 
938
- def reload
939
- clear_association_cache
940
- _, attributes = search(:value => id).find do |_dn, _attributes|
941
- dn == _dn
942
- end
943
- if attributes.nil?
944
- raise EntryNotFound, _("Can't find DN '%s' to reload") % dn
945
- end
946
-
947
- @ldap_data.update(attributes)
948
- classes, attributes = extract_object_class(attributes)
949
- self.classes = classes
950
- self.attributes = attributes
951
- @new_entry = false
952
- self
953
- end
954
-
955
892
  def [](name, force_array=false)
956
893
  if name == "dn"
957
894
  array_of(dn, force_array)
@@ -964,12 +901,6 @@ module ActiveLdap
964
901
  set_attribute(name, value)
965
902
  end
966
903
 
967
- def each
968
- @data.each do |key, values|
969
- yield(key.dup, values.dup)
970
- end
971
- end
972
-
973
904
  def bind(config_or_password={}, config_or_ignore=nil, &block)
974
905
  if config_or_password.is_a?(String)
975
906
  config = (config_or_ignore || {}).merge(:password => config_or_password)
@@ -1004,6 +935,9 @@ module ActiveLdap
1004
935
  def clear_object_class_based_cache
1005
936
  @entry_attribute = nil
1006
937
  @real_names = {}
938
+ @changed_attributes.reject! do |key, _|
939
+ not attribute_method?(key)
940
+ end
1007
941
  end
1008
942
 
1009
943
  def schema
@@ -1130,10 +1064,26 @@ module ActiveLdap
1130
1064
  classes, attributes = extract_object_class(attributes)
1131
1065
  self.classes = classes
1132
1066
  self.dn = dn
1133
- self.attributes = attributes
1067
+ initialize_attributes(attributes)
1134
1068
  yield self if block_given?
1135
1069
  end
1136
1070
 
1071
+ def initialize_attributes(attributes)
1072
+ _schema = _local_entry_attribute = nil
1073
+ targets = sanitize_for_mass_assignment(attributes)
1074
+ targets.each do |key, value|
1075
+ unless have_attribute?(key)
1076
+ _schema ||= schema
1077
+ attribute = _schema.attribute(key)
1078
+ _local_entry_attribute ||= local_entry_attribute
1079
+ _local_entry_attribute.register(attribute)
1080
+ end
1081
+ set_attribute(key, value)
1082
+ end
1083
+ @changed_attributes.clear
1084
+ end
1085
+ private :initialize_attributes
1086
+
1137
1087
  def instantiate(args)
1138
1088
  dn, attributes, options = args
1139
1089
  options ||= {}
@@ -1180,83 +1130,11 @@ module ActiveLdap
1180
1130
  @dn_split_value = nil
1181
1131
  @connection ||= nil
1182
1132
  @_hashing = false
1133
+ @previously_changed = []
1134
+ @changed_attributes = {}
1183
1135
  clear_connection_based_cache
1184
1136
  end
1185
1137
 
1186
- # get_attribute
1187
- #
1188
- # Return the value of the attribute called by method_missing?
1189
- def get_attribute(name, force_array=false)
1190
- name, value = get_attribute_before_type_cast(name, force_array)
1191
- return value if name.nil?
1192
- attribute = schema.attribute(name)
1193
- type_cast(attribute, value)
1194
- end
1195
-
1196
- def type_cast(attribute, value)
1197
- case value
1198
- when Hash
1199
- result = {}
1200
- value.each do |option, val|
1201
- result[option] = type_cast(attribute, val)
1202
- end
1203
- if result.size == 1 and result.has_key?("binary")
1204
- result["binary"]
1205
- else
1206
- result
1207
- end
1208
- when Array
1209
- value.collect do |val|
1210
- type_cast(attribute, val)
1211
- end
1212
- else
1213
- attribute.type_cast(value)
1214
- end
1215
- end
1216
-
1217
- def get_attribute_before_type_cast(name, force_array=false)
1218
- name = to_real_attribute_name(name)
1219
-
1220
- value = @data[name]
1221
- value = [] if value.nil?
1222
- [name, array_of(value, force_array)]
1223
- end
1224
-
1225
- def get_attribute_as_query(name, force_array=false)
1226
- name, value = get_attribute_before_type_cast(name, force_array)
1227
- if force_array
1228
- value.collect {|x| !false_value?(x)}
1229
- else
1230
- !false_value?(value)
1231
- end
1232
- end
1233
-
1234
- def false_value?(value)
1235
- value.nil? or value == false or value == [] or
1236
- value == "false" or value == "FALSE" or value == ""
1237
- end
1238
-
1239
- # set_attribute
1240
- #
1241
- # Set the value of the attribute called by method_missing?
1242
- def set_attribute(name, value)
1243
- real_name = to_real_attribute_name(name)
1244
- _dn_attribute = nil
1245
- valid_dn_attribute = true
1246
- begin
1247
- _dn_attribute = dn_attribute
1248
- rescue DistinguishedNameInvalid
1249
- valid_dn_attribute = false
1250
- end
1251
- if valid_dn_attribute and real_name == _dn_attribute
1252
- real_name, value = register_new_dn_attribute(real_name, value)
1253
- end
1254
- raise UnknownAttribute.new(name) if real_name.nil?
1255
-
1256
- @data[real_name] = value
1257
- @simplified_data = nil
1258
- end
1259
-
1260
1138
  def register_new_dn_attribute(name, value)
1261
1139
  @dn = nil
1262
1140
  @dn_is_base = false
@@ -1281,6 +1159,7 @@ module ActiveLdap
1281
1159
  @base_value = nil
1282
1160
  attr, value = bases[0].to_a[0]
1283
1161
  @dn_attribute = attr
1162
+ _ = value # for suppress a warning on Ruby 1.9.3
1284
1163
  else
1285
1164
  new_name ||= @dn_attribute || dn_attribute_of_class
1286
1165
  new_name = to_real_attribute_name(new_name)