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