activeldap 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -14
- data/benchmark/README.md +64 -0
- data/benchmark/{bench-al.rb → bench-backend.rb} +6 -22
- data/benchmark/bench-instantiate.rb +98 -0
- data/benchmark/config.yaml.sample +2 -2
- data/doc/text/news.textile +38 -0
- data/lib/active_ldap.rb +17 -8
- data/lib/active_ldap/association/has_many_wrap.rb +15 -2
- data/lib/active_ldap/attribute_methods.rb +23 -0
- data/lib/active_ldap/attribute_methods/before_type_cast.rb +24 -0
- data/lib/active_ldap/attribute_methods/dirty.rb +43 -0
- data/lib/active_ldap/attribute_methods/query.rb +31 -0
- data/lib/active_ldap/attribute_methods/read.rb +44 -0
- data/lib/active_ldap/attribute_methods/write.rb +38 -0
- data/lib/active_ldap/attributes.rb +18 -26
- data/lib/active_ldap/base.rb +42 -163
- data/lib/active_ldap/connection.rb +6 -1
- data/lib/active_ldap/get_text.rb +18 -7
- data/lib/active_ldap/operations.rb +63 -49
- data/lib/active_ldap/persistence.rb +17 -0
- data/lib/active_ldap/railtie.rb +3 -0
- data/lib/active_ldap/schema.rb +2 -0
- data/lib/active_ldap/schema/syntaxes.rb +7 -7
- data/lib/active_ldap/validations.rb +2 -2
- data/lib/active_ldap/version.rb +3 -0
- data/lib/active_ldap/xml.rb +24 -7
- data/lib/rails/generators/active_ldap/model/model_generator.rb +3 -3
- data/test/add-phonetic-attribute-options-to-slapd.ldif +10 -0
- data/test/al-test-utils.rb +428 -0
- data/test/command.rb +111 -0
- data/test/config.yaml.sample +6 -0
- data/test/fixtures/lower_case_object_class_schema.rb +802 -0
- data/test/run-test.rb +29 -0
- data/test/test_associations.rb +37 -0
- data/test/test_base.rb +113 -51
- data/test/test_dirty.rb +84 -0
- data/test/test_ldif.rb +0 -1
- data/test/test_load.rb +0 -1
- data/test/test_reflection.rb +7 -14
- data/test/test_syntax.rb +104 -43
- data/test/test_usermod-binary-del.rb +1 -1
- data/test/test_usermod-lang-add.rb +0 -1
- metadata +272 -224
- data/lib/active_ldap/get_text_fallback.rb +0 -60
- 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
|
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
|
-
|
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
|
-
|
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
|
-
|
169
|
+
sanitized_attributes
|
178
170
|
end
|
179
171
|
|
180
172
|
def normalize_attribute_name(name)
|
data/lib/active_ldap/base.rb
CHANGED
@@ -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
|
-
#
|
348
|
-
#
|
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
|
-
|
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
|
-
|
916
|
-
|
917
|
-
|
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
|
-
|
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)
|