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,100 @@
|
|
|
1
|
+
module ActiveLdap
|
|
2
|
+
module Persistence
|
|
3
|
+
# new_entry?
|
|
4
|
+
#
|
|
5
|
+
# Return whether the entry is new entry in LDAP or not
|
|
6
|
+
def new_entry?
|
|
7
|
+
@new_entry
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Return whether the entry is saved entry or not.
|
|
11
|
+
def persisted?
|
|
12
|
+
not new_entry?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# destroy
|
|
16
|
+
#
|
|
17
|
+
# Delete this entry from LDAP
|
|
18
|
+
def destroy
|
|
19
|
+
# TODO: support deleting relations
|
|
20
|
+
delete
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def delete(options={})
|
|
24
|
+
if persisted?
|
|
25
|
+
default_options = {
|
|
26
|
+
:connection => connection,
|
|
27
|
+
}
|
|
28
|
+
self.class.delete_entry(dn, default_options.merge(options))
|
|
29
|
+
end
|
|
30
|
+
@new_entry = true
|
|
31
|
+
freeze
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# save
|
|
35
|
+
#
|
|
36
|
+
# Save and validate this object into LDAP
|
|
37
|
+
# either adding or replacing attributes
|
|
38
|
+
# TODO: Relative DN support
|
|
39
|
+
def save(*)
|
|
40
|
+
create_or_update
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def save!(*)
|
|
44
|
+
unless create_or_update
|
|
45
|
+
raise EntryNotSaved, _("entry %s can't be saved") % dn
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def create_or_update
|
|
50
|
+
new_entry? ? create : update
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create
|
|
54
|
+
prepare_data_for_saving do |data, ldap_data|
|
|
55
|
+
attributes = collect_all_attributes(data)
|
|
56
|
+
add_entry(dn, attributes)
|
|
57
|
+
@new_entry = false
|
|
58
|
+
true
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def update
|
|
63
|
+
prepare_data_for_saving do |data, ldap_data|
|
|
64
|
+
new_dn_value, attributes = collect_modified_attributes(ldap_data, data)
|
|
65
|
+
modify_entry(@original_dn, attributes)
|
|
66
|
+
if new_dn_value
|
|
67
|
+
old_dn_base = DN.parse(@original_dn).parent
|
|
68
|
+
new_dn_base = dn.clone.parent
|
|
69
|
+
if old_dn_base == new_dn_base
|
|
70
|
+
new_superior = nil
|
|
71
|
+
else
|
|
72
|
+
new_superior = new_dn_base
|
|
73
|
+
end
|
|
74
|
+
modify_rdn_entry(@original_dn,
|
|
75
|
+
"#{dn_attribute}=#{DN.escape_value(new_dn_value)}",
|
|
76
|
+
true,
|
|
77
|
+
new_superior)
|
|
78
|
+
end
|
|
79
|
+
true
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def reload
|
|
84
|
+
clear_association_cache
|
|
85
|
+
_, attributes = search(:value => id).find do |_dn, _attributes|
|
|
86
|
+
dn == _dn
|
|
87
|
+
end
|
|
88
|
+
if attributes.nil?
|
|
89
|
+
raise EntryNotFound, _("Can't find DN '%s' to reload") % dn
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
@ldap_data.update(attributes)
|
|
93
|
+
classes, attributes = extract_object_class(attributes)
|
|
94
|
+
self.classes = classes
|
|
95
|
+
self.attributes = attributes
|
|
96
|
+
@new_entry = false
|
|
97
|
+
self
|
|
98
|
+
end
|
|
99
|
+
end # Persistence
|
|
100
|
+
end # ActiveLdap
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module ActiveLdap
|
|
2
|
+
module Populate
|
|
3
|
+
module_function
|
|
4
|
+
def ensure_base(base_class=nil)
|
|
5
|
+
base_class ||= Base
|
|
6
|
+
return unless base_class.search(:scope => :base).empty?
|
|
7
|
+
|
|
8
|
+
base_dn = DN.parse(base_class.base)
|
|
9
|
+
suffixes = []
|
|
10
|
+
|
|
11
|
+
base_dn.rdns.reverse_each do |rdn|
|
|
12
|
+
name, value = rdn.to_a[0]
|
|
13
|
+
prefix = suffixes.join(",")
|
|
14
|
+
suffixes.unshift("#{name}=#{value}")
|
|
15
|
+
next unless name == "dc"
|
|
16
|
+
begin
|
|
17
|
+
ensure_dc(value, prefix, base_class)
|
|
18
|
+
rescue ActiveLdap::OperationNotPermitted
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ensure_ou(name, base_class=nil)
|
|
24
|
+
base_class ||= Base
|
|
25
|
+
name = name.to_s if name.is_a?(DN)
|
|
26
|
+
name = name.gsub(/\Aou\s*=\s*/i, '')
|
|
27
|
+
|
|
28
|
+
ou_class = Class.new(base_class)
|
|
29
|
+
ou_class.ldap_mapping(:dn_attribute => "ou",
|
|
30
|
+
:prefix => "",
|
|
31
|
+
:classes => ["top", "organizationalUnit"])
|
|
32
|
+
return if ou_class.exist?(name)
|
|
33
|
+
ou_class.new(name).save!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ensure_dc(name, prefix, base_class=nil)
|
|
37
|
+
base_class ||= Base
|
|
38
|
+
name = name.to_s if name.is_a?(DN)
|
|
39
|
+
name = name.gsub(/\Adc\s*=\s*/i, '')
|
|
40
|
+
|
|
41
|
+
dc_class = Class.new(base_class)
|
|
42
|
+
dc_class.ldap_mapping(:dn_attribute => "dc",
|
|
43
|
+
:prefix => "",
|
|
44
|
+
:scope => :base,
|
|
45
|
+
:classes => ["top", "dcObject", "organization"])
|
|
46
|
+
dc_class.base = prefix
|
|
47
|
+
return if dc_class.exist?(name)
|
|
48
|
+
dc = dc_class.new(name)
|
|
49
|
+
dc.o = dc.dc
|
|
50
|
+
dc.save!
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require "locale"
|
|
2
|
+
require 'active_ldap'
|
|
3
|
+
require 'rails'
|
|
4
|
+
|
|
5
|
+
Locale.init(:driver => :cgi)
|
|
6
|
+
|
|
7
|
+
module ActiveLdap
|
|
8
|
+
class Railtie < Rails::Railtie
|
|
9
|
+
config.app_generators.orm :active_ldap
|
|
10
|
+
|
|
11
|
+
initializer "active_ldap.setup_connection" do
|
|
12
|
+
ldap_configuration_file = Rails.root.join('config', 'ldap.yml')
|
|
13
|
+
if File.exist?(ldap_configuration_file)
|
|
14
|
+
configurations = YAML::load(ERB.new(IO.read(ldap_configuration_file)).result)
|
|
15
|
+
ActiveLdap::Base.configurations = configurations
|
|
16
|
+
ActiveLdap::Base.setup_connection
|
|
17
|
+
else
|
|
18
|
+
ActiveLdap::Base.class_eval do
|
|
19
|
+
format =_("You should run 'rails generator active_ldap:scaffold' to make %s.")
|
|
20
|
+
logger.error(format % ldap_configuration_file)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
initializer "active_ldap.logger", :before => "active_ldap.setup_connection" do
|
|
26
|
+
ActiveLdap::Base.logger ||= ::Rails.logger
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
initializer "active_ldap.action_view_helper" do
|
|
30
|
+
class ::ActionView::Base
|
|
31
|
+
include ActiveLdap::Helper
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Expose Ldap runtime to controller for logging.
|
|
36
|
+
initializer "active_ldap.log_runtime" do |app|
|
|
37
|
+
require "active_ldap/railties/controller_runtime"
|
|
38
|
+
ActiveSupport.on_load(:action_controller) do
|
|
39
|
+
include ActiveLdap::Railties::ControllerRuntime
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'active_support/core_ext/module/attr_internal'
|
|
2
|
+
require 'active_ldap/log_subscriber'
|
|
3
|
+
|
|
4
|
+
module ActiveLdap
|
|
5
|
+
module Railties
|
|
6
|
+
module ControllerRuntime #:nodoc:
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
protected
|
|
10
|
+
|
|
11
|
+
attr_internal :ldap_runtime
|
|
12
|
+
|
|
13
|
+
def process_action(action, *args)
|
|
14
|
+
# We also need to reset the runtime before each action
|
|
15
|
+
# because of queries in middleware or in cases we are streaming
|
|
16
|
+
# and it won't be cleaned up by the method below.
|
|
17
|
+
ActiveLdap::LogSubscriber.reset_runtime
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def cleanup_view_runtime
|
|
22
|
+
if ActiveLdap::Base.connected?
|
|
23
|
+
ldap_rt_before_render = ActiveLdap::LogSubscriber.reset_runtime
|
|
24
|
+
runtime = super
|
|
25
|
+
ldap_rt_after_render = ActiveLdap::LogSubscriber.reset_runtime
|
|
26
|
+
self.ldap_runtime = ldap_rt_before_render + ldap_rt_after_render
|
|
27
|
+
runtime - ldap_rt_after_render
|
|
28
|
+
else
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def append_info_to_payload(payload)
|
|
34
|
+
super
|
|
35
|
+
payload[:ldap_runtime] = ldap_runtime
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module ClassMethods
|
|
39
|
+
def log_process_action(payload)
|
|
40
|
+
messages, ldap_runtime = super, payload[:ldap_runtime]
|
|
41
|
+
messages << ("ActiveLdap: %.1fms" % ldap_runtime.to_f) if ldap_runtime
|
|
42
|
+
messages
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
module ActiveLdap
|
|
2
|
+
class Schema
|
|
3
|
+
include GetTextSupport
|
|
4
|
+
|
|
5
|
+
def initialize(entries)
|
|
6
|
+
@entries = normalize_entries(entries || {})
|
|
7
|
+
@schema_info = {}
|
|
8
|
+
@class_attributes_info = {}
|
|
9
|
+
@cache = {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def ids(group)
|
|
13
|
+
ensure_parse(group)
|
|
14
|
+
info, ids, aliases = ensure_schema_info(group)
|
|
15
|
+
_ = info = aliases # for suppress a warning on Ruby 1.9.3
|
|
16
|
+
ids.keys
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def names(group)
|
|
20
|
+
alias_map(group).keys
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def exist_name?(group, name)
|
|
24
|
+
alias_map(group).has_key?(normalize_schema_name(name))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def resolve_name(group, name)
|
|
28
|
+
alias_map(group)[normalize_schema_name(name)]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# fetch
|
|
32
|
+
#
|
|
33
|
+
# This is just like LDAP::Schema#attribute except that it allows
|
|
34
|
+
# look up in any of the given keys.
|
|
35
|
+
# e.g.
|
|
36
|
+
# fetch('attributeTypes', 'cn', 'DESC')
|
|
37
|
+
# fetch('ldapSyntaxes', '1.3.6.1.4.1.1466.115.121.1.5', 'DESC')
|
|
38
|
+
def fetch(group, id_or_name, attribute_name)
|
|
39
|
+
return [] if attribute_name.empty?
|
|
40
|
+
attribute_name = normalize_attribute_name(attribute_name)
|
|
41
|
+
value = entry(group, id_or_name)[attribute_name]
|
|
42
|
+
value ? value.dup : []
|
|
43
|
+
end
|
|
44
|
+
alias_method :[], :fetch
|
|
45
|
+
|
|
46
|
+
NUMERIC_OID_RE = "\\d[\\d\\.]+"
|
|
47
|
+
DESCRIPTION_RE = "[a-zA-Z][a-zA-Z\\d\\-]*"
|
|
48
|
+
OID_RE = "(?:#{NUMERIC_OID_RE}|#{DESCRIPTION_RE}-oid)"
|
|
49
|
+
def entry(group, id_or_name)
|
|
50
|
+
return {} if group.empty? or id_or_name.empty?
|
|
51
|
+
|
|
52
|
+
unless @entries.has_key?(group)
|
|
53
|
+
raise ArgumentError, _("Unknown schema group: %s") % group
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Initialize anything that is required
|
|
57
|
+
info, ids, aliases = ensure_schema_info(group)
|
|
58
|
+
_ = info # for suppress a warning on Ruby 1.9.3
|
|
59
|
+
id, name = determine_id_or_name(id_or_name, aliases)
|
|
60
|
+
|
|
61
|
+
# Check already parsed options first
|
|
62
|
+
return ids[id] if ids.has_key?(id)
|
|
63
|
+
|
|
64
|
+
schemata = @entries[group] || []
|
|
65
|
+
while schema = schemata.shift
|
|
66
|
+
next unless /\A\s*\(\s*(#{OID_RE})\s*(.*)\s*\)\s*\z/ =~ schema
|
|
67
|
+
schema_id = $1
|
|
68
|
+
rest = $2
|
|
69
|
+
|
|
70
|
+
if ids.has_key?(schema_id)
|
|
71
|
+
attributes = ids[schema_id]
|
|
72
|
+
else
|
|
73
|
+
attributes = {}
|
|
74
|
+
ids[schema_id] = attributes
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
parse_attributes(rest, attributes)
|
|
78
|
+
(attributes["NAME"] || []).each do |v|
|
|
79
|
+
normalized_name = normalize_schema_name(v)
|
|
80
|
+
aliases[normalized_name] = schema_id
|
|
81
|
+
id = schema_id if id.nil? and name == normalized_name
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
break if id == schema_id
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
ids[id || aliases[name]] || {}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def attribute(name)
|
|
91
|
+
cache([:attribute, name]) do
|
|
92
|
+
Attribute.new(name, self)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def attributes
|
|
97
|
+
cache([:attributes]) do
|
|
98
|
+
names("attributeTypes").collect do |name|
|
|
99
|
+
attribute(name)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def attribute_type(name, attribute_name)
|
|
105
|
+
cache([:attribute_type, name, attribute_name]) do
|
|
106
|
+
fetch("attributeTypes", name, attribute_name)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def object_class(name)
|
|
111
|
+
cache([:object_class, name]) do
|
|
112
|
+
ObjectClass.new(name, self)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def object_classes
|
|
117
|
+
cache([:object_classes]) do
|
|
118
|
+
names("objectClasses").collect do |name|
|
|
119
|
+
object_class(name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def object_class_attribute(name, attribute_name)
|
|
125
|
+
cache([:object_class_attribute, name, attribute_name]) do
|
|
126
|
+
fetch("objectClasses", name, attribute_name)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def dit_content_rule_attribute(name, attribute_name)
|
|
131
|
+
cache([:dit_content_rule_attribute, name, attribute_name]) do
|
|
132
|
+
fetch("dITContentRules", name, attribute_name)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def ldap_syntax(name)
|
|
137
|
+
cache([:ldap_syntax, name]) do
|
|
138
|
+
Syntax.new(name, self)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def ldap_syntaxes
|
|
143
|
+
cache([:ldap_syntaxes]) do
|
|
144
|
+
ids("ldapSyntaxes").collect do |id|
|
|
145
|
+
ldap_syntax(id)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def ldap_syntax_attribute(name, attribute_name)
|
|
151
|
+
cache([:ldap_syntax_attribute, name, attribute_name]) do
|
|
152
|
+
fetch("ldapSyntaxes", name, attribute_name)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def dump(output=nil)
|
|
157
|
+
require 'pp'
|
|
158
|
+
output ||= STDOUT
|
|
159
|
+
if output.respond_to?(:write)
|
|
160
|
+
PP.pp(@entries, output)
|
|
161
|
+
else
|
|
162
|
+
open(output, "w") {|out| PP.pp(@entries, out)}
|
|
163
|
+
end
|
|
164
|
+
nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
private
|
|
168
|
+
def cache(key)
|
|
169
|
+
(@cache[key] ||= [yield])[0]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def ensure_schema_info(group)
|
|
173
|
+
@schema_info[group] ||= {:ids => {}, :aliases => {}}
|
|
174
|
+
info = @schema_info[group]
|
|
175
|
+
[info, info[:ids], info[:aliases]]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def determine_id_or_name(id_or_name, aliases)
|
|
179
|
+
if /\A[\d\.]+\z/ =~ id_or_name
|
|
180
|
+
id = id_or_name
|
|
181
|
+
name = nil
|
|
182
|
+
else
|
|
183
|
+
name = normalize_schema_name(id_or_name)
|
|
184
|
+
id = aliases[name]
|
|
185
|
+
end
|
|
186
|
+
[id, name]
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# from RFC 2252
|
|
190
|
+
attribute_type_description_reserved_names =
|
|
191
|
+
["NAME", "DESC", "OBSOLETE", "SUP", "EQUALITY", "ORDERING", "SUBSTR",
|
|
192
|
+
"SYNTAX", "SINGLE-VALUE", "COLLECTIVE", "NO-USER-MODIFICATION", "USAGE"]
|
|
193
|
+
syntax_description_reserved_names = ["DESC"]
|
|
194
|
+
object_class_description_reserved_names =
|
|
195
|
+
["NAME", "DESC", "OBSOLETE", "SUP", "ABSTRACT", "STRUCTURAL",
|
|
196
|
+
"AUXILIARY", "MUST", "MAY"]
|
|
197
|
+
matching_rule_description_reserved_names =
|
|
198
|
+
["NAME", "DESC", "OBSOLETE", "SYNTAX"]
|
|
199
|
+
matching_rule_use_description_reserved_names =
|
|
200
|
+
["NAME", "DESC", "OBSOLETE", "APPLIES"]
|
|
201
|
+
private_experiment_reserved_names = ["X-[A-Z\\-_]+"]
|
|
202
|
+
reserved_names =
|
|
203
|
+
(attribute_type_description_reserved_names +
|
|
204
|
+
syntax_description_reserved_names +
|
|
205
|
+
object_class_description_reserved_names +
|
|
206
|
+
matching_rule_description_reserved_names +
|
|
207
|
+
matching_rule_use_description_reserved_names +
|
|
208
|
+
private_experiment_reserved_names).uniq
|
|
209
|
+
RESERVED_NAMES_RE = /(?:#{reserved_names.join('|')})/
|
|
210
|
+
|
|
211
|
+
def parse_attributes(str, attributes)
|
|
212
|
+
str.scan(/([A-Z\-_]+)\s+
|
|
213
|
+
(?:\(\s*(\w[\w\-;]*(?:\s+\$\s+\w[\w\-;]*)*)\s*\)|
|
|
214
|
+
\(\s*([^\)]*)\s*\)|
|
|
215
|
+
'([^\']*)'|
|
|
216
|
+
((?!#{RESERVED_NAMES_RE})[a-zA-Z][a-zA-Z\d\-;]*)|
|
|
217
|
+
(\d[\d\.\{\}]+)|
|
|
218
|
+
()
|
|
219
|
+
)/x
|
|
220
|
+
) do |name, multi_amp, multi, string, literal, syntax, no_value|
|
|
221
|
+
case
|
|
222
|
+
when multi_amp
|
|
223
|
+
values = multi_amp.rstrip.split(/\s*\$\s*/)
|
|
224
|
+
when multi
|
|
225
|
+
values = multi.scan(/\s*'([^\']*)'\s*/).collect {|value| value[0]}
|
|
226
|
+
when string
|
|
227
|
+
values = [string]
|
|
228
|
+
when literal
|
|
229
|
+
values = [literal]
|
|
230
|
+
when syntax
|
|
231
|
+
values = [syntax]
|
|
232
|
+
when no_value
|
|
233
|
+
values = ["TRUE"]
|
|
234
|
+
end
|
|
235
|
+
attributes[normalize_attribute_name(name)] ||= []
|
|
236
|
+
attributes[normalize_attribute_name(name)].concat(values)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def alias_map(group)
|
|
241
|
+
ensure_parse(group)
|
|
242
|
+
return {} if @schema_info[group].nil?
|
|
243
|
+
@schema_info[group][:aliases] || {}
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def ensure_parse(group)
|
|
247
|
+
return if @entries[group].nil?
|
|
248
|
+
unless @entries[group].empty?
|
|
249
|
+
fetch(group, 'nonexistent', 'nonexistent')
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def normalize_schema_name(name)
|
|
254
|
+
name.downcase.sub(/;.*$/, '')
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def normalize_attribute_name(name)
|
|
258
|
+
name.upcase.gsub(/_/, "-")
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def default_entries
|
|
262
|
+
{
|
|
263
|
+
"objectClasses" => [],
|
|
264
|
+
"attributeTypes" => [],
|
|
265
|
+
"ldapSyntaxes" => [],
|
|
266
|
+
"dITContentRules" => [],
|
|
267
|
+
"matchingRules" => [],
|
|
268
|
+
}
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def normalize_entries(entries)
|
|
272
|
+
normalized_entries = default_entries
|
|
273
|
+
normalized_keys = normalized_entries.keys
|
|
274
|
+
entries.each do |name, values|
|
|
275
|
+
normalized_name = normalized_keys.find do |key|
|
|
276
|
+
key.downcase == name
|
|
277
|
+
end
|
|
278
|
+
normalized_entries[normalized_name || name] = values
|
|
279
|
+
end
|
|
280
|
+
normalized_entries
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
class Entry
|
|
284
|
+
include Comparable
|
|
285
|
+
|
|
286
|
+
attr_reader :id, :name, :aliases, :description
|
|
287
|
+
def initialize(name, schema, group)
|
|
288
|
+
@schema = schema
|
|
289
|
+
@name, *@aliases = attribute("NAME", name)
|
|
290
|
+
@name ||= name
|
|
291
|
+
@id = @schema.resolve_name(group, @name)
|
|
292
|
+
collect_info
|
|
293
|
+
@schema = nil
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def eql?(other)
|
|
297
|
+
self.class == other.class and
|
|
298
|
+
(id == other.id or
|
|
299
|
+
(id.nil? and other.nil? and name == other.name))
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def hash
|
|
303
|
+
id.nil? ? name.hash : id.hash
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def <=>(other)
|
|
307
|
+
name <=> other.name
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def to_param
|
|
311
|
+
name
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
class Syntax < Entry
|
|
316
|
+
attr_reader :length
|
|
317
|
+
def initialize(id, schema)
|
|
318
|
+
if /\{(\d+)\}\z/ =~ id
|
|
319
|
+
id = $PREMATCH
|
|
320
|
+
@length = Integer($1)
|
|
321
|
+
else
|
|
322
|
+
@length = nil
|
|
323
|
+
end
|
|
324
|
+
super(id, schema, "ldapSyntaxes")
|
|
325
|
+
@id = id
|
|
326
|
+
@name = nil if @name == @id
|
|
327
|
+
@validator = Syntaxes[@id]
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def binary_transfer_required?
|
|
331
|
+
@binary_transfer_required
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def human_readable?
|
|
335
|
+
@human_readable
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def valid?(value)
|
|
339
|
+
validate(value).nil?
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def validate(value)
|
|
343
|
+
if @validator
|
|
344
|
+
@validator.validate(value)
|
|
345
|
+
else
|
|
346
|
+
nil
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def type_cast(value)
|
|
351
|
+
if @validator
|
|
352
|
+
@validator.type_cast(value)
|
|
353
|
+
else
|
|
354
|
+
value
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def normalize_value(value)
|
|
359
|
+
if @validator
|
|
360
|
+
@validator.normalize_value(value)
|
|
361
|
+
else
|
|
362
|
+
value
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def <=>(other)
|
|
367
|
+
id <=> other.id
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def to_param
|
|
371
|
+
id
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
private
|
|
375
|
+
def attribute(attribute_name, name=@name)
|
|
376
|
+
@schema.ldap_syntax_attribute(name, attribute_name)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def collect_info
|
|
380
|
+
@description = attribute("DESC")[0]
|
|
381
|
+
@binary_transfer_required =
|
|
382
|
+
(attribute('X-BINARY-TRANSFER-REQUIRED')[0] == 'TRUE')
|
|
383
|
+
@human_readable = (attribute('X-NOT-HUMAN-READABLE')[0] != 'TRUE')
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
class Attribute < Entry
|
|
388
|
+
include GetTextSupport
|
|
389
|
+
include HumanReadable
|
|
390
|
+
|
|
391
|
+
attr_reader :super_attribute
|
|
392
|
+
def initialize(name, schema)
|
|
393
|
+
super(name, schema, "attributeTypes")
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# read_only?
|
|
397
|
+
#
|
|
398
|
+
# Returns true if an attribute is read-only
|
|
399
|
+
# NO-USER-MODIFICATION
|
|
400
|
+
def read_only?
|
|
401
|
+
@read_only
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# single_value?
|
|
405
|
+
#
|
|
406
|
+
# Returns true if an attribute can only have one
|
|
407
|
+
# value defined
|
|
408
|
+
# SINGLE-VALUE
|
|
409
|
+
def single_value?
|
|
410
|
+
@single_value
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# binary?
|
|
414
|
+
#
|
|
415
|
+
# Returns true if the given attribute's syntax
|
|
416
|
+
# is X-NOT-HUMAN-READABLE or X-BINARY-TRANSFER-REQUIRED
|
|
417
|
+
def binary?
|
|
418
|
+
@binary
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# binary_required?
|
|
422
|
+
#
|
|
423
|
+
# Returns true if the value MUST be transferred in binary
|
|
424
|
+
def binary_required?
|
|
425
|
+
@binary_required
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# directory_operation?
|
|
429
|
+
#
|
|
430
|
+
# Returns true if an attribute is directory operation.
|
|
431
|
+
# It means that USAGE contains directoryOperation.
|
|
432
|
+
def directory_operation?
|
|
433
|
+
@directory_operation
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def syntax
|
|
437
|
+
@derived_syntax
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def valid?(value)
|
|
441
|
+
validate(value).nil?
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def validate(value)
|
|
445
|
+
error_info = validate_each_value(value)
|
|
446
|
+
return error_info if error_info
|
|
447
|
+
begin
|
|
448
|
+
normalize_value(value)
|
|
449
|
+
nil
|
|
450
|
+
rescue AttributeValueInvalid
|
|
451
|
+
[$!.message]
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def type_cast(value)
|
|
456
|
+
send_to_syntax(value, :type_cast, value)
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def normalize_value(value)
|
|
460
|
+
normalize_value_internal(value, false)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def syntax_description
|
|
464
|
+
send_to_syntax(nil, :description)
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def human_attribute_name
|
|
468
|
+
self.class.human_attribute_name(self)
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
def human_attribute_description
|
|
472
|
+
self.class.human_attribute_description(self)
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
def to_hash
|
|
476
|
+
{
|
|
477
|
+
:read_only => read_only?,
|
|
478
|
+
:single_value => single_value?,
|
|
479
|
+
:binary => binary?,
|
|
480
|
+
:binary_required => binary_required?,
|
|
481
|
+
:directory_operation => directory_operation?,
|
|
482
|
+
:syntax => syntax,
|
|
483
|
+
:syntax_description => syntax_description,
|
|
484
|
+
}
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
private
|
|
488
|
+
def attribute(attribute_name, name=@name)
|
|
489
|
+
@schema.attribute_type(name, attribute_name)
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def collect_info
|
|
493
|
+
@description = attribute("DESC")[0]
|
|
494
|
+
@super_attribute = attribute("SUP")[0]
|
|
495
|
+
if @super_attribute
|
|
496
|
+
@super_attribute = @schema.attribute(@super_attribute)
|
|
497
|
+
@super_attribute = nil if @super_attribute.id.nil?
|
|
498
|
+
end
|
|
499
|
+
@read_only = attribute('NO-USER-MODIFICATION')[0] == 'TRUE'
|
|
500
|
+
@single_value = attribute('SINGLE-VALUE')[0] == 'TRUE'
|
|
501
|
+
@syntax = attribute("SYNTAX")[0]
|
|
502
|
+
@syntax = @schema.ldap_syntax(@syntax) if @syntax
|
|
503
|
+
if @syntax
|
|
504
|
+
@binary_required = @syntax.binary_transfer_required?
|
|
505
|
+
@binary = (@binary_required or !@syntax.human_readable?)
|
|
506
|
+
@derived_syntax = @syntax
|
|
507
|
+
else
|
|
508
|
+
@binary_required = false
|
|
509
|
+
@binary = false
|
|
510
|
+
@derived_syntax = nil
|
|
511
|
+
@derived_syntax = @super_attribute.syntax if @super_attribute
|
|
512
|
+
end
|
|
513
|
+
@directory_operation = attribute("USAGE").include?("directoryOperation")
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
def send_to_syntax(default_value, method_name, *args)
|
|
517
|
+
_syntax = syntax
|
|
518
|
+
if _syntax
|
|
519
|
+
_syntax.send(method_name, *args)
|
|
520
|
+
else
|
|
521
|
+
default_value
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
def validate_each_value(value, option=nil)
|
|
526
|
+
failed_reason = nil
|
|
527
|
+
case value
|
|
528
|
+
when Hash
|
|
529
|
+
original_option = option
|
|
530
|
+
value.each do |sub_option, val|
|
|
531
|
+
opt = [original_option, sub_option].compact.join(";")
|
|
532
|
+
failed_reason, option = validate_each_value(val, opt)
|
|
533
|
+
break if failed_reason
|
|
534
|
+
end
|
|
535
|
+
when Array
|
|
536
|
+
original_option = option
|
|
537
|
+
value.each do |val|
|
|
538
|
+
failed_reason, option = validate_each_value(val, original_option)
|
|
539
|
+
break if failed_reason
|
|
540
|
+
end
|
|
541
|
+
else
|
|
542
|
+
failed_reason = send_to_syntax(nil, :validate, value)
|
|
543
|
+
end
|
|
544
|
+
return nil if failed_reason.nil?
|
|
545
|
+
[failed_reason, option]
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
def normalize_value_internal(value, have_binary_mark)
|
|
549
|
+
case value
|
|
550
|
+
when Array
|
|
551
|
+
normalize_array_value(value, have_binary_mark)
|
|
552
|
+
when Hash
|
|
553
|
+
normalize_hash_value(value, have_binary_mark)
|
|
554
|
+
else
|
|
555
|
+
if value.blank?
|
|
556
|
+
value = []
|
|
557
|
+
else
|
|
558
|
+
value = send_to_syntax(value, :normalize_value, value)
|
|
559
|
+
end
|
|
560
|
+
if !have_binary_mark and binary_required?
|
|
561
|
+
[{'binary' => value}]
|
|
562
|
+
else
|
|
563
|
+
value.is_a?(Array) ? value : [value]
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def normalize_array_value(value, have_binary_mark)
|
|
569
|
+
if single_value? and value.reject {|v| v.is_a?(Hash)}.size > 1
|
|
570
|
+
format = _("Attribute %s can only have a single value: %s")
|
|
571
|
+
message = format % [human_attribute_name, value.inspect]
|
|
572
|
+
raise AttributeValueInvalid.new(self, value, message)
|
|
573
|
+
end
|
|
574
|
+
if value.empty?
|
|
575
|
+
if !have_binary_mark and binary_required?
|
|
576
|
+
[{'binary' => value}]
|
|
577
|
+
else
|
|
578
|
+
value
|
|
579
|
+
end
|
|
580
|
+
else
|
|
581
|
+
value.collect do |entry|
|
|
582
|
+
normalize_value_internal(entry, have_binary_mark)[0]
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
def normalize_hash_value(value, have_binary_mark)
|
|
588
|
+
if value.size > 1
|
|
589
|
+
format = _("Attribute %s: Hash must have one key-value pair only: %s")
|
|
590
|
+
message = format % [human_attribute_name, value.inspect]
|
|
591
|
+
raise AttributeValueInvalid.new(self, value, message)
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
if !have_binary_mark and binary_required? and !have_binary_key?(value)
|
|
595
|
+
[append_binary_key(value)]
|
|
596
|
+
else
|
|
597
|
+
key = value.keys[0]
|
|
598
|
+
have_binary_mark ||= key == "binary"
|
|
599
|
+
[{key => normalize_value_internal(value.values[0], have_binary_mark)}]
|
|
600
|
+
end
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
def have_binary_key?(hash)
|
|
604
|
+
key, value = hash.to_a[0]
|
|
605
|
+
return true if key == "binary"
|
|
606
|
+
return have_binary_key?(value) if value.is_a?(Hash)
|
|
607
|
+
false
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
def append_binary_key(hash)
|
|
611
|
+
key, value = hash.to_a[0]
|
|
612
|
+
if value.is_a?(Hash)
|
|
613
|
+
append_binary_key(value)
|
|
614
|
+
else
|
|
615
|
+
hash.merge(key => {"binary" => value})
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
class ObjectClass < Entry
|
|
621
|
+
attr_reader :super_classes
|
|
622
|
+
def initialize(name, schema)
|
|
623
|
+
super(name, schema, "objectClasses")
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
def super_class?(object_class)
|
|
627
|
+
@super_classes.include?(object_class)
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def must(include_super_class=true)
|
|
631
|
+
if include_super_class
|
|
632
|
+
@all_must
|
|
633
|
+
else
|
|
634
|
+
@must
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
def may(include_super_class=true)
|
|
639
|
+
if include_super_class
|
|
640
|
+
@all_may
|
|
641
|
+
else
|
|
642
|
+
@may
|
|
643
|
+
end
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
private
|
|
647
|
+
def collect_info
|
|
648
|
+
@description = attribute("DESC")[0]
|
|
649
|
+
@super_classes = collect_super_classes
|
|
650
|
+
@must, @may, @all_must, @all_may = collect_attributes
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
def collect_super_classes
|
|
654
|
+
super_classes = attribute('SUP')
|
|
655
|
+
loop do
|
|
656
|
+
start_size = super_classes.size
|
|
657
|
+
new_super_classes = []
|
|
658
|
+
super_classes.each do |super_class|
|
|
659
|
+
new_super_classes.concat(attribute('SUP', super_class))
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
super_classes.concat(new_super_classes)
|
|
663
|
+
super_classes.uniq!
|
|
664
|
+
break if super_classes.size == start_size
|
|
665
|
+
end
|
|
666
|
+
super_classes.collect do |name|
|
|
667
|
+
@schema.object_class(name)
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
UNWRITABLE_MUST_ATTRIBUTES = ["nTSecurityDescriptor"]
|
|
672
|
+
def collect_attributes
|
|
673
|
+
must = attribute('MUST').reject do |name|
|
|
674
|
+
UNWRITABLE_MUST_ATTRIBUTES.include?(name)
|
|
675
|
+
end.uniq
|
|
676
|
+
must = must.collect {|name| @schema.attribute(name)}
|
|
677
|
+
may = attribute('MAY').uniq.collect {|name| @schema.attribute(name)}
|
|
678
|
+
|
|
679
|
+
all_must = must.dup
|
|
680
|
+
all_may = may.dup
|
|
681
|
+
@super_classes.each do |super_class|
|
|
682
|
+
all_must.concat(super_class.must(false))
|
|
683
|
+
all_may.concat(super_class.may(false))
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
# Clean out the dupes.
|
|
687
|
+
all_must.uniq!
|
|
688
|
+
all_may.uniq!
|
|
689
|
+
|
|
690
|
+
[must, may, all_must, all_may]
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
def attribute(attribute_name, name=@name)
|
|
694
|
+
@schema.object_class_attribute(name, attribute_name) +
|
|
695
|
+
@schema.dit_content_rule_attribute(name, attribute_name)
|
|
696
|
+
end
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
require 'active_ldap/schema/syntaxes'
|