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.
- checksums.yaml +7 -0
- data/.yardopts +6 -0
- data/COPYING +340 -0
- data/Gemfile +12 -0
- data/LICENSE +59 -0
- data/README.textile +140 -0
- data/TODO +32 -0
- data/benchmark/README.md +64 -0
- data/benchmark/bench-backend.rb +247 -0
- data/benchmark/bench-instantiate.rb +98 -0
- data/benchmark/config.yaml.sample +5 -0
- data/doc/text/development.textile +54 -0
- data/doc/text/news.textile +811 -0
- data/doc/text/rails.textile +144 -0
- data/doc/text/tutorial.textile +1010 -0
- data/examples/config.yaml.example +5 -0
- data/examples/example.der +0 -0
- data/examples/example.jpg +0 -0
- data/examples/groupadd +41 -0
- data/examples/groupdel +35 -0
- data/examples/groupls +49 -0
- data/examples/groupmod +42 -0
- data/examples/lpasswd +55 -0
- data/examples/objects/group.rb +13 -0
- data/examples/objects/ou.rb +4 -0
- data/examples/objects/user.rb +20 -0
- data/examples/ouadd +38 -0
- data/examples/useradd +45 -0
- data/examples/useradd-binary +53 -0
- data/examples/userdel +34 -0
- data/examples/userls +50 -0
- data/examples/usermod +42 -0
- data/examples/usermod-binary-add +50 -0
- data/examples/usermod-binary-add-time +54 -0
- data/examples/usermod-binary-del +48 -0
- data/examples/usermod-lang-add +43 -0
- data/lib/active_ldap.rb +85 -0
- data/lib/active_ldap/action_controller/ldap_benchmarking.rb +55 -0
- data/lib/active_ldap/acts/tree.rb +78 -0
- data/lib/active_ldap/adapter/base.rb +707 -0
- data/lib/active_ldap/adapter/jndi.rb +184 -0
- data/lib/active_ldap/adapter/jndi_connection.rb +185 -0
- data/lib/active_ldap/adapter/ldap.rb +290 -0
- data/lib/active_ldap/adapter/ldap_ext.rb +105 -0
- data/lib/active_ldap/adapter/net_ldap.rb +309 -0
- data/lib/active_ldap/adapter/net_ldap_ext.rb +23 -0
- data/lib/active_ldap/association/belongs_to.rb +47 -0
- data/lib/active_ldap/association/belongs_to_many.rb +58 -0
- data/lib/active_ldap/association/children.rb +21 -0
- data/lib/active_ldap/association/collection.rb +105 -0
- data/lib/active_ldap/association/has_many.rb +31 -0
- data/lib/active_ldap/association/has_many_utils.rb +44 -0
- data/lib/active_ldap/association/has_many_wrap.rb +75 -0
- data/lib/active_ldap/association/proxy.rb +107 -0
- data/lib/active_ldap/associations.rb +205 -0
- 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 +176 -0
- data/lib/active_ldap/base.rb +1410 -0
- data/lib/active_ldap/callbacks.rb +71 -0
- data/lib/active_ldap/command.rb +49 -0
- data/lib/active_ldap/compatible.rb +44 -0
- data/lib/active_ldap/configuration.rb +147 -0
- data/lib/active_ldap/connection.rb +299 -0
- data/lib/active_ldap/distinguished_name.rb +291 -0
- data/lib/active_ldap/entry_attribute.rb +78 -0
- data/lib/active_ldap/escape.rb +12 -0
- data/lib/active_ldap/get_text.rb +20 -0
- data/lib/active_ldap/get_text/parser.rb +161 -0
- data/lib/active_ldap/helper.rb +92 -0
- data/lib/active_ldap/human_readable.rb +133 -0
- data/lib/active_ldap/ldap_error.rb +74 -0
- data/lib/active_ldap/ldif.rb +930 -0
- data/lib/active_ldap/log_subscriber.rb +50 -0
- data/lib/active_ldap/object_class.rb +95 -0
- data/lib/active_ldap/operations.rb +624 -0
- data/lib/active_ldap/persistence.rb +100 -0
- data/lib/active_ldap/populate.rb +53 -0
- data/lib/active_ldap/railtie.rb +43 -0
- data/lib/active_ldap/railties/controller_runtime.rb +48 -0
- data/lib/active_ldap/schema.rb +701 -0
- data/lib/active_ldap/schema/syntaxes.rb +422 -0
- data/lib/active_ldap/timeout.rb +75 -0
- data/lib/active_ldap/timeout_stub.rb +17 -0
- data/lib/active_ldap/user_password.rb +99 -0
- data/lib/active_ldap/validations.rb +200 -0
- data/lib/active_ldap/version.rb +3 -0
- data/lib/active_ldap/xml.rb +139 -0
- data/lib/rails/generators/active_ldap/model/USAGE +18 -0
- data/lib/rails/generators/active_ldap/model/model_generator.rb +47 -0
- data/lib/rails/generators/active_ldap/model/templates/model_active_ldap.rb +3 -0
- data/lib/rails/generators/active_ldap/scaffold/scaffold_generator.rb +14 -0
- data/lib/rails/generators/active_ldap/scaffold/templates/ldap.yml +19 -0
- data/po/en/active-ldap.po +4029 -0
- data/po/ja/active-ldap.po +4060 -0
- 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 +34 -0
- data/test/test_acts_as_tree.rb +60 -0
- data/test/test_adapter.rb +121 -0
- data/test/test_associations.rb +701 -0
- data/test/test_attributes.rb +117 -0
- data/test/test_base.rb +1214 -0
- data/test/test_base_per_instance.rb +61 -0
- data/test/test_bind.rb +62 -0
- data/test/test_callback.rb +31 -0
- data/test/test_configuration.rb +40 -0
- data/test/test_connection.rb +82 -0
- data/test/test_connection_per_class.rb +112 -0
- data/test/test_connection_per_dn.rb +112 -0
- data/test/test_dirty.rb +98 -0
- data/test/test_dn.rb +172 -0
- data/test/test_find.rb +176 -0
- data/test/test_groupadd.rb +50 -0
- data/test/test_groupdel.rb +46 -0
- data/test/test_groupls.rb +107 -0
- data/test/test_groupmod.rb +51 -0
- data/test/test_ldif.rb +1890 -0
- data/test/test_load.rb +133 -0
- data/test/test_lpasswd.rb +75 -0
- data/test/test_object_class.rb +74 -0
- data/test/test_persistence.rb +131 -0
- data/test/test_reflection.rb +175 -0
- data/test/test_schema.rb +559 -0
- data/test/test_syntax.rb +444 -0
- data/test/test_user.rb +217 -0
- data/test/test_user_password.rb +108 -0
- data/test/test_useradd-binary.rb +62 -0
- data/test/test_useradd.rb +57 -0
- data/test/test_userdel.rb +48 -0
- data/test/test_userls.rb +91 -0
- data/test/test_usermod-binary-add-time.rb +65 -0
- data/test/test_usermod-binary-add.rb +64 -0
- data/test/test_usermod-binary-del.rb +66 -0
- data/test/test_usermod-lang-add.rb +59 -0
- data/test/test_usermod.rb +58 -0
- data/test/test_validation.rb +274 -0
- 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
|