powerhome-activeldap 3.2.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 (145) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +6 -0
  3. data/COPYING +340 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE +59 -0
  6. data/README.textile +140 -0
  7. data/TODO +32 -0
  8. data/benchmark/README.md +64 -0
  9. data/benchmark/bench-backend.rb +247 -0
  10. data/benchmark/bench-instantiate.rb +98 -0
  11. data/benchmark/config.yaml.sample +5 -0
  12. data/doc/text/development.textile +54 -0
  13. data/doc/text/news.textile +811 -0
  14. data/doc/text/rails.textile +144 -0
  15. data/doc/text/tutorial.textile +1010 -0
  16. data/examples/config.yaml.example +5 -0
  17. data/examples/example.der +0 -0
  18. data/examples/example.jpg +0 -0
  19. data/examples/groupadd +41 -0
  20. data/examples/groupdel +35 -0
  21. data/examples/groupls +49 -0
  22. data/examples/groupmod +42 -0
  23. data/examples/lpasswd +55 -0
  24. data/examples/objects/group.rb +13 -0
  25. data/examples/objects/ou.rb +4 -0
  26. data/examples/objects/user.rb +20 -0
  27. data/examples/ouadd +38 -0
  28. data/examples/useradd +45 -0
  29. data/examples/useradd-binary +53 -0
  30. data/examples/userdel +34 -0
  31. data/examples/userls +50 -0
  32. data/examples/usermod +42 -0
  33. data/examples/usermod-binary-add +50 -0
  34. data/examples/usermod-binary-add-time +54 -0
  35. data/examples/usermod-binary-del +48 -0
  36. data/examples/usermod-lang-add +43 -0
  37. data/lib/active_ldap.rb +85 -0
  38. data/lib/active_ldap/action_controller/ldap_benchmarking.rb +55 -0
  39. data/lib/active_ldap/acts/tree.rb +78 -0
  40. data/lib/active_ldap/adapter/base.rb +707 -0
  41. data/lib/active_ldap/adapter/jndi.rb +184 -0
  42. data/lib/active_ldap/adapter/jndi_connection.rb +185 -0
  43. data/lib/active_ldap/adapter/ldap.rb +290 -0
  44. data/lib/active_ldap/adapter/ldap_ext.rb +105 -0
  45. data/lib/active_ldap/adapter/net_ldap.rb +309 -0
  46. data/lib/active_ldap/adapter/net_ldap_ext.rb +23 -0
  47. data/lib/active_ldap/association/belongs_to.rb +47 -0
  48. data/lib/active_ldap/association/belongs_to_many.rb +58 -0
  49. data/lib/active_ldap/association/children.rb +21 -0
  50. data/lib/active_ldap/association/collection.rb +105 -0
  51. data/lib/active_ldap/association/has_many.rb +31 -0
  52. data/lib/active_ldap/association/has_many_utils.rb +44 -0
  53. data/lib/active_ldap/association/has_many_wrap.rb +75 -0
  54. data/lib/active_ldap/association/proxy.rb +107 -0
  55. data/lib/active_ldap/associations.rb +205 -0
  56. data/lib/active_ldap/attribute_methods.rb +23 -0
  57. data/lib/active_ldap/attribute_methods/before_type_cast.rb +24 -0
  58. data/lib/active_ldap/attribute_methods/dirty.rb +43 -0
  59. data/lib/active_ldap/attribute_methods/query.rb +31 -0
  60. data/lib/active_ldap/attribute_methods/read.rb +44 -0
  61. data/lib/active_ldap/attribute_methods/write.rb +38 -0
  62. data/lib/active_ldap/attributes.rb +176 -0
  63. data/lib/active_ldap/base.rb +1410 -0
  64. data/lib/active_ldap/callbacks.rb +71 -0
  65. data/lib/active_ldap/command.rb +49 -0
  66. data/lib/active_ldap/compatible.rb +44 -0
  67. data/lib/active_ldap/configuration.rb +147 -0
  68. data/lib/active_ldap/connection.rb +299 -0
  69. data/lib/active_ldap/distinguished_name.rb +291 -0
  70. data/lib/active_ldap/entry_attribute.rb +78 -0
  71. data/lib/active_ldap/escape.rb +12 -0
  72. data/lib/active_ldap/get_text.rb +20 -0
  73. data/lib/active_ldap/get_text/parser.rb +161 -0
  74. data/lib/active_ldap/helper.rb +92 -0
  75. data/lib/active_ldap/human_readable.rb +133 -0
  76. data/lib/active_ldap/ldap_error.rb +74 -0
  77. data/lib/active_ldap/ldif.rb +930 -0
  78. data/lib/active_ldap/log_subscriber.rb +50 -0
  79. data/lib/active_ldap/object_class.rb +95 -0
  80. data/lib/active_ldap/operations.rb +624 -0
  81. data/lib/active_ldap/persistence.rb +100 -0
  82. data/lib/active_ldap/populate.rb +53 -0
  83. data/lib/active_ldap/railtie.rb +43 -0
  84. data/lib/active_ldap/railties/controller_runtime.rb +48 -0
  85. data/lib/active_ldap/schema.rb +701 -0
  86. data/lib/active_ldap/schema/syntaxes.rb +422 -0
  87. data/lib/active_ldap/timeout.rb +75 -0
  88. data/lib/active_ldap/timeout_stub.rb +17 -0
  89. data/lib/active_ldap/user_password.rb +99 -0
  90. data/lib/active_ldap/validations.rb +200 -0
  91. data/lib/active_ldap/version.rb +3 -0
  92. data/lib/active_ldap/xml.rb +139 -0
  93. data/lib/rails/generators/active_ldap/model/USAGE +18 -0
  94. data/lib/rails/generators/active_ldap/model/model_generator.rb +47 -0
  95. data/lib/rails/generators/active_ldap/model/templates/model_active_ldap.rb +3 -0
  96. data/lib/rails/generators/active_ldap/scaffold/scaffold_generator.rb +14 -0
  97. data/lib/rails/generators/active_ldap/scaffold/templates/ldap.yml +19 -0
  98. data/po/en/active-ldap.po +4029 -0
  99. data/po/ja/active-ldap.po +4060 -0
  100. data/test/add-phonetic-attribute-options-to-slapd.ldif +10 -0
  101. data/test/al-test-utils.rb +428 -0
  102. data/test/command.rb +111 -0
  103. data/test/config.yaml.sample +6 -0
  104. data/test/fixtures/lower_case_object_class_schema.rb +802 -0
  105. data/test/run-test.rb +34 -0
  106. data/test/test_acts_as_tree.rb +60 -0
  107. data/test/test_adapter.rb +121 -0
  108. data/test/test_associations.rb +701 -0
  109. data/test/test_attributes.rb +117 -0
  110. data/test/test_base.rb +1214 -0
  111. data/test/test_base_per_instance.rb +61 -0
  112. data/test/test_bind.rb +62 -0
  113. data/test/test_callback.rb +31 -0
  114. data/test/test_configuration.rb +40 -0
  115. data/test/test_connection.rb +82 -0
  116. data/test/test_connection_per_class.rb +112 -0
  117. data/test/test_connection_per_dn.rb +112 -0
  118. data/test/test_dirty.rb +98 -0
  119. data/test/test_dn.rb +172 -0
  120. data/test/test_find.rb +176 -0
  121. data/test/test_groupadd.rb +50 -0
  122. data/test/test_groupdel.rb +46 -0
  123. data/test/test_groupls.rb +107 -0
  124. data/test/test_groupmod.rb +51 -0
  125. data/test/test_ldif.rb +1890 -0
  126. data/test/test_load.rb +133 -0
  127. data/test/test_lpasswd.rb +75 -0
  128. data/test/test_object_class.rb +74 -0
  129. data/test/test_persistence.rb +131 -0
  130. data/test/test_reflection.rb +175 -0
  131. data/test/test_schema.rb +559 -0
  132. data/test/test_syntax.rb +444 -0
  133. data/test/test_user.rb +217 -0
  134. data/test/test_user_password.rb +108 -0
  135. data/test/test_useradd-binary.rb +62 -0
  136. data/test/test_useradd.rb +57 -0
  137. data/test/test_userdel.rb +48 -0
  138. data/test/test_userls.rb +91 -0
  139. data/test/test_usermod-binary-add-time.rb +65 -0
  140. data/test/test_usermod-binary-add.rb +64 -0
  141. data/test/test_usermod-binary-del.rb +66 -0
  142. data/test/test_usermod-lang-add.rb +59 -0
  143. data/test/test_usermod.rb +58 -0
  144. data/test/test_validation.rb +274 -0
  145. metadata +379 -0
@@ -0,0 +1,205 @@
1
+ require 'active_ldap/association/belongs_to'
2
+ require 'active_ldap/association/belongs_to_many'
3
+ require 'active_ldap/association/has_many'
4
+ require 'active_ldap/association/has_many_wrap'
5
+
6
+ module ActiveLdap
7
+ # Associations
8
+ #
9
+ # Associations provides the class methods needed for
10
+ # the extension classes to create methods using
11
+ # belongs_to and has_many
12
+ module Associations
13
+ def self.append_features(base)
14
+ super
15
+ base.extend(ClassMethods)
16
+ base.class_attribute(:associations)
17
+ base.associations ||= []
18
+ end
19
+
20
+ module ClassMethods
21
+ def set_associated_class(name, klass)
22
+ @associated_classes ||= {}
23
+ @associated_classes[name.to_s] = klass
24
+ end
25
+
26
+ def associated_class(name)
27
+ @associated_classes[name.to_s]
28
+ end
29
+
30
+ # belongs_to
31
+ #
32
+ # This defines a method for an extension class map its DN key
33
+ # attribute value on to multiple items which reference it by
34
+ # |:foreign_key| in the other LDAP entry covered by class
35
+ # |:class_name|.
36
+ #
37
+ # Example:
38
+ # belongs_to :groups, :class_name => "Group",
39
+ # :many => "memberUid" # Group#memberUid
40
+ # # :primary_key => "uid" # User#uid
41
+ # ## deprecated since 1.1.0. Use :primary_key instead.
42
+ # ## :foreign_key => "uid" # User#uid
43
+ # # dn attribute value is used by default
44
+ # belongs_to :primary_group, :class_name => "Group",
45
+ # :foreign_key => "gidNumber", # User#gidNumber
46
+ # :primary_key => "gidNumber" # Group#gidNumber
47
+ #
48
+ def belongs_to(association_id, options={})
49
+ validate_belongs_to_options(options)
50
+ klass = options[:class]
51
+ klass ||= (options[:class_name] || association_id.to_s).classify
52
+ foreign_key = options[:foreign_key]
53
+ primary_key = options[:primary_key]
54
+ many = options[:many]
55
+ set_associated_class(association_id, klass)
56
+
57
+ opts = {
58
+ :association_id => association_id,
59
+ :foreign_key_name => foreign_key,
60
+ :primary_key_name => primary_key,
61
+ :many => many,
62
+ :extend => options[:extend],
63
+ }
64
+ if opts[:many]
65
+ association_class = Association::BelongsToMany
66
+ foreign_key_name = opts[:foreign_key_name]
67
+ if foreign_key_name
68
+ message = _(":foreign_key belongs_to(:many) option is " \
69
+ "deprecated since 1.1.0. Use :primary_key instead.")
70
+ ActiveSupport::Deprecation.warn(message)
71
+ opts[:primary_key_name] ||= foreign_key_name
72
+ end
73
+ opts[:primary_key_name] ||= dn_attribute
74
+ else
75
+ association_class = Association::BelongsTo
76
+ opts[:foreign_key_name] ||= "#{association_id}_id"
77
+
78
+ before_save(<<-EOC)
79
+ if defined?(@#{association_id})
80
+ association = @#{association_id}
81
+ if association and association.updated?
82
+ self[association.__send__(:primary_key)] =
83
+ association[#{opts[:foreign_key_name].dump}]
84
+ end
85
+ end
86
+ EOC
87
+ end
88
+
89
+ association_accessor(association_id) do |target|
90
+ association_class.new(target, opts)
91
+ end
92
+ end
93
+
94
+
95
+ # has_many
96
+ #
97
+ # This defines a method for an extension class expand an
98
+ # existing multi-element attribute into ActiveLdap objects.
99
+ # This discards any calls which result in entries that
100
+ # don't exist in LDAP!
101
+ #
102
+ # Example:
103
+ # has_many :primary_members, :class_name => "User",
104
+ # :primary_key => "gidNumber", # Group#gidNumber
105
+ # :foreign_key => "gidNumber" # User#gidNumber
106
+ # ## deprecated since 1.1.0. Those options
107
+ # ## are inverted.
108
+ # # :primary_key => "gidNumber", # User#gidNumber
109
+ # # :foreign_key => "gidNumber" # Group#gidNumber
110
+ # has_many :members, :class_name => "User",
111
+ # :wrap => "memberUid" # Group#memberUid
112
+ def has_many(association_id, options = {})
113
+ validate_has_many_options(options)
114
+ klass = options[:class]
115
+ klass ||= (options[:class_name] || association_id.to_s).classify
116
+ foreign_key = options[:foreign_key]
117
+ primary_key = options[:primary_key]
118
+ set_associated_class(association_id, klass)
119
+
120
+ opts = {
121
+ :association_id => association_id,
122
+ :foreign_key_name => foreign_key,
123
+ :primary_key_name => primary_key,
124
+ :wrap => options[:wrap],
125
+ :extend => options[:extend],
126
+ }
127
+ if opts[:wrap]
128
+ association_class = Association::HasManyWrap
129
+ else
130
+ association_class = Association::HasMany
131
+ primary_key_name = opts[:primary_key_name]
132
+ foreign_key_name = opts[:foreign_key_name]
133
+ if primary_key_name != foreign_key_name and
134
+ primary_key_name != "dn" and
135
+ !new.have_attribute?(primary_key_name)
136
+ message = _(":primary_key and :foreign_key has_many options are " \
137
+ "inverted their mean since 1.1.0. Please invert them.")
138
+ ActiveSupport::Deprecation.warn(message)
139
+ opts[:foreign_key_name] = primary_key_name
140
+ opts[:primary_key_name] = foreign_key_name
141
+ end
142
+ end
143
+
144
+ association_accessor(association_id) do |target|
145
+ association_class.new(target, opts)
146
+ end
147
+ end
148
+
149
+ private
150
+ def association_accessor(name, &make_association)
151
+ define_method("__make_#{name}") do
152
+ make_association.call(self)
153
+ end
154
+ associations << name
155
+ association_reader(name, &make_association)
156
+ association_writer(name, &make_association)
157
+ end
158
+
159
+ def association_reader(name, &make_association)
160
+ class_eval(<<-EOM, __FILE__, __LINE__ + 1)
161
+ def #{name}
162
+ @#{name} ||= __make_#{name}
163
+ end
164
+ EOM
165
+ end
166
+
167
+ def association_writer(name, &make_association)
168
+ class_eval(<<-EOM, __FILE__, __LINE__ + 1)
169
+ def #{name}=(new_value)
170
+ association = defined?(@#{name}) ? @#{name} : nil
171
+ association ||= __make_#{name}
172
+ association.replace(new_value)
173
+ @#{name} = new_value.nil? ? nil : association
174
+ @#{name}
175
+ end
176
+ EOM
177
+ end
178
+
179
+ VALID_BELONGS_TO_OPTIONS = [:class, :class_name,
180
+ :foreign_key, :primary_key, :many,
181
+ :extend]
182
+ def validate_belongs_to_options(options)
183
+ options.assert_valid_keys(VALID_BELONGS_TO_OPTIONS)
184
+ end
185
+
186
+ VALID_HAS_MANY_OPTIONS = [:class, :class_name,
187
+ :foreign_key, :primary_key, :wrap,
188
+ :extend]
189
+ def validate_has_many_options(options)
190
+ options.assert_valid_keys(VALID_HAS_MANY_OPTIONS)
191
+ end
192
+ end
193
+
194
+ def clear_association_cache
195
+ return if new_record?
196
+ (self.class.associations || []).each do |association|
197
+ instance_variable_set("@#{association}", nil)
198
+ end
199
+ end
200
+ end
201
+
202
+ module Association
203
+ autoload :Children, 'active_ldap/association/children'
204
+ end
205
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveLdap
2
+ module AttributeMethods
3
+ extend ActiveSupport::Concern
4
+ include ActiveModel::AttributeMethods
5
+
6
+ def methods(singleton_methods = true)
7
+ target_names = entry_attribute.all_names
8
+ target_names -= ['objectClass', 'objectClass'.underscore]
9
+ super + target_names.uniq.collect do |attr|
10
+ self.class.attribute_method_matchers.collect do |matcher|
11
+ :"#{matcher.prefix}#{attr}#{matcher.suffix}"
12
+ end
13
+ end.flatten
14
+ end
15
+
16
+ protected
17
+
18
+ # overiding ActiveModel::AttributeMethods
19
+ def attribute_method?(method_name)
20
+ have_attribute?(method_name, ['objectClass'])
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ module ActiveLdap
2
+ module AttributeMethods
3
+ module BeforeTypeCast
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ attribute_method_suffix '_before_type_cast'
8
+ end
9
+
10
+ protected
11
+ def attribute_before_type_cast(attr)
12
+ get_attribute_before_type_cast(attr)[1]
13
+ end
14
+
15
+ def get_attribute_before_type_cast(name, force_array=false)
16
+ name = to_real_attribute_name(name)
17
+
18
+ value = @data[name]
19
+ value = [] if value.nil?
20
+ [name, array_of(value, force_array)]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ #
2
+ module ActiveLdap
3
+ module AttributeMethods
4
+ module Dirty
5
+ extend ActiveSupport::Concern
6
+ include ActiveModel::Dirty
7
+
8
+ # Attempts to +save+ the record and clears changed attributes if successful.
9
+ def save(*) #:nodoc:
10
+ succeeded = super
11
+ if succeeded
12
+ @previously_changed = changes
13
+ @changed_attributes.clear
14
+ end
15
+ succeeded
16
+ end
17
+
18
+ # Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
19
+ def save!(*) #:nodoc:
20
+ super.tap do
21
+ @previously_changed = changes
22
+ @changed_attributes.clear
23
+ end
24
+ end
25
+
26
+ # <tt>reload</tt> the record and clears changed attributes.
27
+ def reload(*) #:nodoc:
28
+ super.tap do
29
+ @previously_changed.clear
30
+ @changed_attributes.clear
31
+ end
32
+ end
33
+
34
+ protected
35
+ def set_attribute(name, value)
36
+ if name and name != "objectClass"
37
+ attribute_will_change!(name) unless value == get_attribute(name)
38
+ end
39
+ super
40
+ end
41
+ end
42
+ end
43
+ end
@@ -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
@@ -0,0 +1,176 @@
1
+ module ActiveLdap
2
+ module Attributes
3
+ def self.included(base)
4
+ base.class_eval do
5
+ extend(ClassMethods)
6
+ extend(Normalizable)
7
+ include(Normalizable)
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ def blank_value?(value)
13
+ case value
14
+ when Hash
15
+ value.values.all? {|val| blank_value?(val)}
16
+ when Array
17
+ value.all? {|val| blank_value?(val)}
18
+ when String
19
+ /\A\s*\z/ =~ value
20
+ when nil
21
+ true
22
+ else
23
+ value.blank?
24
+ end
25
+ end
26
+
27
+ def remove_blank_value(value)
28
+ case value
29
+ when Hash
30
+ result = {}
31
+ value.each do |k, v|
32
+ v = remove_blank_value(v)
33
+ next if v.nil?
34
+ result[k] = v
35
+ end
36
+ result = nil if result.blank?
37
+ result
38
+ when Array
39
+ result = []
40
+ value.each do |v|
41
+ v = remove_blank_value(v)
42
+ next if v.nil?
43
+ result << v
44
+ end
45
+ result = nil if result.blank?
46
+ result
47
+ when String
48
+ if /\A\s*\z/ =~ value
49
+ nil
50
+ else
51
+ value
52
+ end
53
+ else
54
+ value
55
+ end
56
+ end
57
+ end
58
+
59
+ module Normalizable
60
+ def normalize_attribute_name(name)
61
+ name.to_s.downcase
62
+ end
63
+
64
+ # Enforce typing:
65
+ # Hashes are for subtypes
66
+ # Arrays are for multiple entries
67
+ def normalize_attribute(name, value)
68
+ if name.nil?
69
+ raise RuntimeError, _('The first argument, name, must not be nil. ' \
70
+ 'Please report this as a bug!')
71
+ end
72
+
73
+ name = normalize_attribute_name(name)
74
+ [name, schema.attribute(name).normalize_value(value)]
75
+ end
76
+
77
+ def unnormalize_attributes(attributes)
78
+ result = {}
79
+ attributes.each do |name, values|
80
+ unnormalize_attribute(name, values, result)
81
+ end
82
+ result
83
+ end
84
+
85
+ def unnormalize_attribute(name, values, result={})
86
+ if values.empty?
87
+ result[name] = []
88
+ else
89
+ values.each do |value|
90
+ if value.is_a?(Hash)
91
+ suffix, real_value = unnormalize_attribute_options(value)
92
+ new_name = name + suffix
93
+ unnormalize_attribute(new_name, real_value, result)
94
+ else
95
+ result[name] ||= []
96
+ if value.is_a?(DN)
97
+ result[name] << value.to_s
98
+ else
99
+ result[name] << value.dup
100
+ end
101
+ end
102
+ end
103
+ end
104
+ result
105
+ end
106
+
107
+ # normalize_attribute_options
108
+ #
109
+ # Makes the Hashized value from the full attribute name
110
+ # e.g. userCertificate;binary => "some_bin"
111
+ # becomes userCertificate => {"binary" => "some_bin"}
112
+ def normalize_attribute_options(attr, value)
113
+ return [attr, value] unless attr.match(/;/)
114
+
115
+ ret_attr, *options = attr.split(/;/)
116
+ [ret_attr,
117
+ [options.reverse.inject(value) {|result, option| {option => result}}]]
118
+ end
119
+
120
+ # unnormalize_attribute_options
121
+ #
122
+ # Unnormalizes all of the subtypes from a given set of nested hashes
123
+ # and returns the attribute suffix and the final true value
124
+ def unnormalize_attribute_options(value)
125
+ options = ''
126
+ ret_val = value
127
+ if value.class == Hash
128
+ options = ';' + value.keys[0]
129
+ ret_val = value[value.keys[0]]
130
+ if ret_val.class == Hash
131
+ sub_options, ret_val = unnormalize_attribute_options(ret_val)
132
+ options += sub_options
133
+ end
134
+ end
135
+ ret_val = [ret_val] unless ret_val.class == Array
136
+ [options, ret_val]
137
+ end
138
+ end
139
+
140
+ private
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 = {}
148
+ needless_attributes = {}
149
+
150
+ _dn_attribute = nil
151
+ begin
152
+ _dn_attribute = dn_attribute_with_fallback
153
+ rescue DistinguishedNameInvalid
154
+ end
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|
163
+ key = _dn_attribute if ["id", "dn"].include?(key.to_s)
164
+ [to_real_attribute_name(key) || key, value]
165
+ end
166
+ sanitized_attributes = sanitized_attributes.reject do |key, value|
167
+ always_needless_attributes[key] or needless_attributes[key]
168
+ end
169
+ sanitized_attributes
170
+ end
171
+
172
+ def normalize_attribute_name(name)
173
+ self.class.normalize_attribute_name(name)
174
+ end
175
+ end
176
+ end