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
@@ -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)