ruby-activeldap 0.8.2 → 0.8.3

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 (83) hide show
  1. data/test/test_adapter.rb +17 -0
  2. data/test/test_associations.rb +19 -0
  3. data/test/test_attributes.rb +2 -1
  4. data/test/test_base.rb +28 -1
  5. data/test/test_base_per_instance.rb +2 -1
  6. data/test/test_callback.rb +2 -2
  7. data/test/test_connection.rb +2 -1
  8. data/test/test_connection_per_dn.rb +81 -0
  9. data/test/test_dn.rb +3 -2
  10. data/test/test_find.rb +35 -1
  11. data/test/test_object_class.rb +12 -1
  12. data/test/test_reflection.rb +16 -10
  13. data/test/test_schema.rb +141 -2
  14. data/test/test_user.rb +14 -4
  15. metadata +7 -104
  16. data/CHANGES +0 -397
  17. data/COPYING +0 -340
  18. data/LICENSE +0 -58
  19. data/Manifest.txt +0 -99
  20. data/README +0 -85
  21. data/Rakefile +0 -70
  22. data/TODO +0 -23
  23. data/benchmark/bench-al.rb +0 -152
  24. data/examples/config.yaml.example +0 -5
  25. data/examples/example.der +0 -0
  26. data/examples/example.jpg +0 -0
  27. data/examples/groupadd +0 -41
  28. data/examples/groupdel +0 -35
  29. data/examples/groupls +0 -49
  30. data/examples/groupmod +0 -42
  31. data/examples/lpasswd +0 -55
  32. data/examples/objects/group.rb +0 -13
  33. data/examples/objects/ou.rb +0 -4
  34. data/examples/objects/user.rb +0 -20
  35. data/examples/ouadd +0 -38
  36. data/examples/useradd +0 -45
  37. data/examples/useradd-binary +0 -50
  38. data/examples/userdel +0 -34
  39. data/examples/userls +0 -50
  40. data/examples/usermod +0 -42
  41. data/examples/usermod-binary-add +0 -47
  42. data/examples/usermod-binary-add-time +0 -51
  43. data/examples/usermod-binary-del +0 -48
  44. data/examples/usermod-lang-add +0 -43
  45. data/lib/active_ldap.rb +0 -964
  46. data/lib/active_ldap/adapter/base.rb +0 -461
  47. data/lib/active_ldap/adapter/ldap.rb +0 -232
  48. data/lib/active_ldap/adapter/ldap_ext.rb +0 -69
  49. data/lib/active_ldap/adapter/net_ldap.rb +0 -288
  50. data/lib/active_ldap/adapter/net_ldap_ext.rb +0 -29
  51. data/lib/active_ldap/association/belongs_to.rb +0 -40
  52. data/lib/active_ldap/association/belongs_to_many.rb +0 -39
  53. data/lib/active_ldap/association/collection.rb +0 -80
  54. data/lib/active_ldap/association/has_many.rb +0 -40
  55. data/lib/active_ldap/association/has_many_wrap.rb +0 -55
  56. data/lib/active_ldap/association/proxy.rb +0 -89
  57. data/lib/active_ldap/associations.rb +0 -162
  58. data/lib/active_ldap/attributes.rb +0 -203
  59. data/lib/active_ldap/base.rb +0 -1510
  60. data/lib/active_ldap/callbacks.rb +0 -19
  61. data/lib/active_ldap/command.rb +0 -46
  62. data/lib/active_ldap/configuration.rb +0 -106
  63. data/lib/active_ldap/connection.rb +0 -142
  64. data/lib/active_ldap/distinguished_name.rb +0 -246
  65. data/lib/active_ldap/ldap_error.rb +0 -74
  66. data/lib/active_ldap/object_class.rb +0 -74
  67. data/lib/active_ldap/schema.rb +0 -299
  68. data/lib/active_ldap/timeout.rb +0 -75
  69. data/lib/active_ldap/timeout_stub.rb +0 -17
  70. data/lib/active_ldap/user_password.rb +0 -92
  71. data/lib/active_ldap/validations.rb +0 -76
  72. data/rails/plugin/active_ldap/README +0 -54
  73. data/rails/plugin/active_ldap/generators/scaffold_al/scaffold_al_generator.rb +0 -7
  74. data/rails/plugin/active_ldap/generators/scaffold_al/templates/ldap.yml +0 -21
  75. data/rails/plugin/active_ldap/init.rb +0 -12
  76. data/test/TODO +0 -2
  77. data/test/al-test-utils.rb +0 -381
  78. data/test/command.rb +0 -62
  79. data/test/config.yaml.sample +0 -6
  80. data/test/run-test.rb +0 -29
  81. data/test/test-unit-ext.rb +0 -2
  82. data/test/test-unit-ext/always-show-result.rb +0 -28
  83. data/test/test-unit-ext/priority.rb +0 -163
@@ -1,74 +0,0 @@
1
- module ActiveLdap
2
- class LdapError < Error
3
- class << self
4
- def define(code, name, target)
5
- klass_name = name.downcase.camelize
6
- target.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
7
- class #{klass_name} < #{self}
8
- CODE = #{code}
9
- def code
10
- CODE
11
- end
12
- end
13
- EOC
14
- target.const_get(klass_name)
15
- end
16
- end
17
-
18
- ERRORS = {}
19
- {
20
- 0x00 => "SUCCESS",
21
- 0x01 => "OPERATIONS_ERROR",
22
- 0x02 => "PROTOCOL_ERROR",
23
- 0x03 => "TIMELIMIT_EXCEEDED",
24
- 0x04 => "SIZELIMIT_EXCEEDED",
25
- 0x05 => "COMPARE_FALSE",
26
- 0x06 => "COMPARE_TRUE",
27
- 0x07 => "AUTH_METHOD_NOT_SUPPORTED",
28
- 0x08 => "STRONG_AUTH_REQUIRED",
29
- 0x09 => "PARTIAL_RESULTS", # LDAPv2+ (not LDAPv3)
30
-
31
- 0x0a => "REFERRAL",
32
- 0x0b => "ADMINLIMIT_EXCEEDED",
33
- 0x0c => "UNAVAILABLE_CRITICAL_EXTENSION",
34
- 0x0d => "CONFIDENTIALITY_REQUIRED",
35
- 0x0e => "LDAP_SASL_BIND_IN_PROGRESS",
36
-
37
- 0x10 => "NO_SUCH_ATTRIBUTE",
38
- 0x11 => "UNDEFINED_TYPE",
39
- 0x12 => "INAPPROPRIATE_MATCHING",
40
- 0x13 => "CONSTRAINT_VIOLATION",
41
- 0x14 => "TYPE_OR_VALUE_EXISTS",
42
- 0x15 => "INVALID_SYNTAX",
43
-
44
- 0x20 => "NO_SUCH_OBJECT",
45
- 0x21 => "ALIAS_PROBLEM",
46
- 0x22 => "INVALID_DN_SYNTAX",
47
- 0x23 => "IS_LEAF",
48
- 0x24 => "ALIAS_DEREF_PROBLEM",
49
-
50
- 0x2F => "PROXY_AUTHZ_FAILURE",
51
- 0x30 => "INAPPROPRIATE_AUTH",
52
- 0x31 => "INVALID_CREDENTIALS",
53
- 0x32 => "INSUFFICIENT_ACCESS",
54
-
55
- 0x33 => "BUSY",
56
- 0x34 => "UNAVAILABLE",
57
- 0x35 => "UNWILLING_TO_PERFORM",
58
- 0x36 => "LOOP_DETECT",
59
-
60
- 0x40 => "NAMING_VIOLATION",
61
- 0x41 => "OBJECT_CLASS_VIOLATION",
62
- 0x42 => "NOT_ALLOWED_ON_NONLEAF",
63
- 0x43 => "NOT_ALLOWED_ON_RDN",
64
- 0x44 => "ALREADY_EXISTS",
65
- 0x45 => "NO_OBJECT_CLASS_MODS",
66
- 0x46 => "RESULTS_TOO_LARGE",
67
- 0x47 => "AFFECTS_MULTIPLE_DSAS",
68
-
69
- 0x50 => "OTHER",
70
- }.each do |code, name|
71
- ERRORS[code] = LdapError.define(code, name, self)
72
- end
73
- end
74
- end
@@ -1,74 +0,0 @@
1
- module ActiveLdap
2
- module ObjectClass
3
- def self.included(base)
4
- base.extend(ClassMethods)
5
- end
6
-
7
- module ClassMethods
8
- end
9
-
10
- def add_class(*target_classes)
11
- replace_class((classes + target_classes.flatten).uniq)
12
- end
13
-
14
- def ensure_recommended_classes
15
- add_class(self.class.recommended_classes)
16
- end
17
-
18
- def remove_class(*target_classes)
19
- replace_class((classes - target_classes.flatten).uniq)
20
- end
21
-
22
- def replace_class(*target_classes)
23
- new_classes = target_classes.flatten.uniq
24
- assert_object_classes(new_classes)
25
- if new_classes.sort != classes.sort
26
- set_attribute('objectClass', new_classes)
27
- end
28
- end
29
-
30
- def classes
31
- (get_attribute('objectClass', true) || []).dup
32
- end
33
-
34
- private
35
- def assert_object_classes(new_classes)
36
- assert_valid_object_class_value_type(new_classes)
37
- assert_valid_object_class_value(new_classes)
38
- assert_have_all_required_classes(new_classes)
39
- end
40
-
41
- def assert_valid_object_class_value_type(new_classes)
42
- invalid_classes = new_classes.reject do |new_class|
43
- new_class.is_a?(String)
44
- end
45
- unless invalid_classes.empty?
46
- message = "Value in objectClass array is not a String"
47
- invalid_classes_info = invalid_classes.collect do |invalid_class|
48
- "#{invalid_class.class}:#{invalid_class.inspect}"
49
- end.join(", ")
50
- raise TypeError, "#{message}: #{invalid_classes_info}"
51
- end
52
- end
53
-
54
- def assert_valid_object_class_value(new_classes)
55
- invalid_classes = new_classes.reject do |new_class|
56
- schema.exist_name?("objectClasses", new_class)
57
- end
58
- unless invalid_classes.empty?
59
- message = "unknown objectClass in LDAP server"
60
- message = "#{message}: #{invalid_classes.join(', ')}"
61
- raise ObjectClassError, message
62
- end
63
- end
64
-
65
- def assert_have_all_required_classes(new_classes)
66
- required_classes = self.class.required_classes - new_classes
67
- unless required_classes.empty?
68
- raise RequiredObjectClassMissed,
69
- "Can't remove required objectClass: " +
70
- required_classes.join(", ")
71
- end
72
- end
73
- end
74
- end
@@ -1,299 +0,0 @@
1
- module ActiveLdap
2
- class Schema
3
- def initialize(entries)
4
- @entries = default_entries.merge(entries || {})
5
- @schema_info = {}
6
- @class_attributes_info = {}
7
- @cache = {}
8
- end
9
-
10
- def names(group)
11
- alias_map(group).keys
12
- end
13
-
14
- def exist_name?(group, name)
15
- alias_map(group).has_key?(normalize_schema_name(name))
16
- end
17
-
18
- # attribute
19
- #
20
- # This is just like LDAP::Schema#attribute except that it allows
21
- # look up in any of the given keys.
22
- # e.g.
23
- # attribute('attributeTypes', 'cn', 'DESC')
24
- # attribute('ldapSyntaxes', '1.3.6.1.4.1.1466.115.121.1.5', 'DESC')
25
- def attribute(group, id_or_name, attribute_name)
26
- return [] if attribute_name.empty?
27
- attribute_name = normalize_attribute_name(attribute_name)
28
- value = attributes(group, id_or_name)[attribute_name]
29
- value ? value.dup : []
30
- end
31
- alias_method :[], :attribute
32
- alias_method :attr, :attribute
33
-
34
- NUMERIC_OID_RE = "\\d[\\d\\.]+"
35
- DESCRIPTION_RE = "[a-zA-Z][a-zA-Z\\d\\-]*"
36
- OID_RE = "(?:#{NUMERIC_OID_RE}|#{DESCRIPTION_RE}-oid)"
37
- def attributes(group, id_or_name)
38
- return {} if group.empty? or id_or_name.empty?
39
-
40
- unless @entries.has_key?(group)
41
- raise ArgumentError, "Unknown schema group: #{group}"
42
- end
43
-
44
- # Initialize anything that is required
45
- info, ids, aliases = ensure_schema_info(group)
46
- id, name = determine_id_or_name(id_or_name, aliases)
47
-
48
- # Check already parsed options first
49
- return ids[id] if ids.has_key?(id)
50
-
51
- schemata = @entries[group] || []
52
- while schema = schemata.shift
53
- next unless /\A\s*\(\s*(#{OID_RE})\s*(.*)\s*\)\s*\z/ =~ schema
54
- schema_id = $1
55
- rest = $2
56
- next if ids.has_key?(schema_id)
57
-
58
- attributes = {}
59
- ids[schema_id] = attributes
60
-
61
- parse_attributes(rest, attributes)
62
- (attributes["NAME"] || []).each do |v|
63
- normalized_name = normalize_schema_name(v)
64
- aliases[normalized_name] = schema_id
65
- id = schema_id if id.nil? and name == normalized_name
66
- end
67
-
68
- break if id == schema_id
69
- end
70
-
71
- ids[id || aliases[name]] || {}
72
- end
73
-
74
- # attribute_aliases
75
- #
76
- # Returns all names from the LDAP schema for the
77
- # attribute given.
78
- def attribute_aliases(name)
79
- cache([:attribute_aliases, name]) do
80
- attribute_type(name, 'NAME')
81
- end
82
- end
83
-
84
- # read_only?
85
- #
86
- # Returns true if an attribute is read-only
87
- # NO-USER-MODIFICATION
88
- def read_only?(name)
89
- cache([:read_only?, name]) do
90
- attribute_type(name, 'NO-USER-MODIFICATION')[0] == 'TRUE'
91
- end
92
- end
93
-
94
- # single_value?
95
- #
96
- # Returns true if an attribute can only have one
97
- # value defined
98
- # SINGLE-VALUE
99
- def single_value?(name)
100
- cache([:single_value?, name]) do
101
- attribute_type(name, 'SINGLE-VALUE')[0] == 'TRUE'
102
- end
103
- end
104
-
105
- # binary?
106
- #
107
- # Returns true if the given attribute's syntax
108
- # is X-NOT-HUMAN-READABLE or X-BINARY-TRANSFER-REQUIRED
109
- def binary?(name)
110
- cache([:binary?, name]) do
111
- # Get syntax OID
112
- syntax = attribute_type(name, 'SYNTAX')[0]
113
- !syntax.nil? and
114
- (ldap_syntax(syntax, 'X-NOT-HUMAN-READABLE') == ["TRUE"] or
115
- ldap_syntax(syntax, 'X-BINARY-TRANSFER-REQUIRED') == ["TRUE"])
116
- end
117
- end
118
-
119
- # binary_required?
120
- #
121
- # Returns true if the value MUST be transferred in binary
122
- def binary_required?(name)
123
- cache([:binary_required?, name]) do
124
- # Get syntax OID
125
- syntax = attribute_type(name, 'SYNTAX')[0]
126
- !syntax.nil? and
127
- ldap_syntax(syntax, 'X-BINARY-TRANSFER-REQUIRED') == ["TRUE"]
128
- end
129
- end
130
-
131
- # class_attributes
132
- #
133
- # Returns an Array of all the valid attributes (but not with full aliases)
134
- # for the given objectClass
135
- def class_attributes(objc)
136
- cache([:class_attributes, objc]) do
137
- # First get all the current level attributes
138
- must = object_class(objc, 'MUST')
139
- may = object_class(objc, 'MAY')
140
-
141
- # Now add all attributes from the parent object (SUPerclasses)
142
- # Hopefully an iterative approach will be pretty speedy
143
- # 1. build complete list of SUPs
144
- # 2. Add attributes from each
145
- sups = object_class(objc, 'SUP')
146
- loop do
147
- start_size = sups.size
148
- new_sups = []
149
- sups.each do |sup|
150
- new_sups.concat(object_class(sup, 'SUP'))
151
- end
152
-
153
- sups.concat(new_sups)
154
- sups.uniq!
155
- break if sups.size == start_size
156
- end
157
- sups.each do |sup|
158
- must.concat(object_class(sup, 'MUST'))
159
- may.concat(object_class(sup, 'MAY'))
160
- end
161
-
162
- # Clean out the dupes.
163
- must.uniq!
164
- may.uniq!
165
- if objc == "inetOrgPerson"
166
- may.collect! do |name|
167
- if name == "x500uniqueIdentifier"
168
- "x500UniqueIdentifier"
169
- else
170
- name
171
- end
172
- end
173
- end
174
-
175
- {:must => must, :may => may}
176
- end
177
- end
178
-
179
- private
180
- def cache(key)
181
- (@cache[key] ||= [yield])[0]
182
- end
183
-
184
- def ensure_schema_info(group)
185
- @schema_info[group] ||= {:ids => {}, :aliases => {}}
186
- info = @schema_info[group]
187
- [info, info[:ids], info[:aliases]]
188
- end
189
-
190
- def determine_id_or_name(id_or_name, aliases)
191
- if /\A[\d\.]+\z/ =~ id_or_name
192
- id = id_or_name
193
- name = nil
194
- else
195
- name = normalize_schema_name(id_or_name)
196
- id = aliases[name]
197
- end
198
- [id, name]
199
- end
200
-
201
- # from RFC 2252
202
- attribute_type_description_reserved_names =
203
- ["NAME", "DESC", "OBSOLETE", "SUP", "EQUALITY", "ORDERING", "SUBSTR",
204
- "SYNTAX", "SINGLE-VALUE", "COLLECTIVE", "NO-USER-MODIFICATION", "USAGE"]
205
- syntax_description_reserved_names = ["DESC"]
206
- object_class_description_reserved_names =
207
- ["NAME", "DESC", "OBSOLETE", "SUP", "ABSTRACT", "STRUCTURAL",
208
- "AUXILIARY", "MUST", "MAY"]
209
- matching_rule_description_reserved_names =
210
- ["NAME", "DESC", "OBSOLETE", "SYNTAX"]
211
- matching_rule_use_description_reserved_names =
212
- ["NAME", "DESC", "OBSOLETE", "APPLIES"]
213
- private_experiment_reserved_names = ["X-[A-Z\\-_]+"]
214
- reserved_names =
215
- (attribute_type_description_reserved_names +
216
- syntax_description_reserved_names +
217
- object_class_description_reserved_names +
218
- matching_rule_description_reserved_names +
219
- matching_rule_use_description_reserved_names +
220
- private_experiment_reserved_names).uniq
221
- RESERVED_NAMES_RE = /(?:#{reserved_names.join('|')})/
222
-
223
- def parse_attributes(str, attributes)
224
- str.scan(/([A-Z\-_]+)\s+
225
- (?:\(\s*([\w\-]+(?:\s+\$\s+[\w\-]+)+)\s*\)|
226
- \(\s*([^\)]*)\s*\)|
227
- '([^\']*)'|
228
- ((?!#{RESERVED_NAMES_RE})[a-zA-Z][a-zA-Z\d\-;]*)|
229
- (\d[\d\.\{\}]+)|
230
- ()
231
- )/x
232
- ) do |name, multi_amp, multi, string, literal, syntax, no_value|
233
- case
234
- when multi_amp
235
- values = multi_amp.rstrip.split(/\s*\$\s*/)
236
- when multi
237
- values = multi.scan(/\s*'([^\']*)'\s*/).collect {|value| value[0]}
238
- when string
239
- values = [string]
240
- when literal
241
- values = [literal]
242
- when syntax
243
- values = [syntax]
244
- when no_value
245
- values = ["TRUE"]
246
- end
247
- attributes[normalize_attribute_name(name)] = values
248
- end
249
- end
250
-
251
- def attribute_type(name, attribute_name)
252
- cache([:attribute_type, name, attribute_name]) do
253
- attribute("attributeTypes", name, attribute_name)
254
- end
255
- end
256
-
257
- def ldap_syntax(name, attribute_name)
258
- return [] unless @entries.has_key?("ldapSyntaxes")
259
- cache([:ldap_syntax, name, attribute_name]) do
260
- attribute("ldapSyntaxes", name, attribute_name)
261
- end
262
- end
263
-
264
- def object_class(name, attribute_name)
265
- cache([:object_class, name, attribute_name]) do
266
- attribute("objectClasses", name, attribute_name)
267
- end
268
- end
269
-
270
- def alias_map(group)
271
- ensure_parse(group)
272
- return {} if @schema_info[group].nil?
273
- @schema_info[group][:aliases] || {}
274
- end
275
-
276
- def ensure_parse(group)
277
- return if @entries[group].nil?
278
- unless @entries[group].empty?
279
- attribute(group, 'nonexistent', 'nonexistent')
280
- end
281
- end
282
-
283
- def normalize_schema_name(name)
284
- name.downcase.sub(/;.*$/, '')
285
- end
286
-
287
- def normalize_attribute_name(name)
288
- name.upcase.gsub(/_/, "-")
289
- end
290
-
291
- def default_entries
292
- {
293
- "objectClasses" => [],
294
- "attributeTypes" => [],
295
- "ldapSyntaxes" => [],
296
- }
297
- end
298
- end # Schema
299
- end
@@ -1,75 +0,0 @@
1
- require 'timeout'
2
-
3
- module Timeout
4
-
5
- # A forking timeout implementation that relies on
6
- # signals to interrupt blocking I/O instead of passing
7
- # that code to run in a separate process.
8
- #
9
- # A process is fork()ed, sleeps for _sec_,
10
- # then sends a ALRM signal to the Process.ppid
11
- # process. ALRM is used to avoid conflicts with sleep()
12
- #
13
- # This overwrites any signal
14
- def Timeout.alarm(sec, exception=Timeout::Error, &block)
15
- return block.call if sec == nil or sec.zero?
16
-
17
-
18
- # Trap an alarm in case it comes before we're ready
19
- orig_alrm = trap(:ALRM, 'IGNORE')
20
-
21
- # Setup a fallback in case of a race condition of an
22
- # alarm before we set the other trap
23
- trap(:ALRM) do
24
- # Don't leave zombies
25
- Process.wait2()
26
- # Restore the original handler
27
- trap('ALRM', orig_alrm)
28
- # Now raise an exception!
29
- raise exception, 'execution expired'
30
- end
31
-
32
- # Spawn the sleeper
33
- pid = Process.fork {
34
- begin
35
- # Sleep x seconds then send SIGALRM
36
- sleep(sec)
37
- # Send alarm!
38
- Process.kill(:ALRM, Process.ppid)
39
- end
40
- exit! 0
41
- }
42
-
43
- # Setup the real handler
44
- trap(:ALRM) do
45
- # Make sure we clean up any zombies
46
- Process.waitpid(pid)
47
- # Restore the original handler
48
- trap(:ALRM, orig_alrm)
49
- # Now raise an exception!
50
- raise exception, 'execution expired'
51
- end
52
-
53
- begin
54
- # Run the code!
55
- return block.call
56
- ensure
57
- # Restore old alarm handler since we're done
58
- trap(:ALRM, orig_alrm)
59
- # Make sure the process is dead
60
- # This may be run twice (trap occurs during execution) so ignore ESRCH
61
- Process.kill(:TERM, pid) rescue Errno::ESRCH
62
- # Don't leave zombies
63
- Process.waitpid(pid) rescue Errno::ECHILD
64
- end
65
- end
66
- end # Timeout
67
-
68
- if __FILE__ == $0
69
- require 'time'
70
- Timeout.alarm(2) do
71
- loop do
72
- p Time.now
73
- end
74
- end
75
- end