root/lib/ldap_shadows/config.rb @ eb96492f
1f9bfec2 | Marc Dequènes (Duck) | #--
|
|
# LdapShadows, a Medium-level LDAP Access Library and Tool.
|
|||
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
|
|||
#
|
|||
# This program is free software: you can redistribute it and/or modify
|
|||
# it under the terms of the GNU General Public License as published by
|
|||
# the Free Software Foundation, either version 3 of the License, or
|
|||
# (at your option) any later version.
|
|||
#
|
|||
# This program is distributed in the hope that it will be useful,
|
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
# GNU General Public License for more details.
|
|||
#
|
|||
# You should have received a copy of the GNU General Public License
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#++
|
|||
require 'ldap_shadows/config_setup'
|
|||
require 'singleton'
|
|||
7f913647 | Marc Dequènes (Duck) | require 'yaml'
|
|
1f9bfec2 | Marc Dequènes (Duck) | require 'kwalify'
|
|
require 'ldap_shadows/shadow'
|
|||
module LdapShadows
|
|||
class Config
|
|||
include Singleton
|
|||
def initialize
|
|||
@global_config = nil
|
|||
@schemas = {}
|
|||
@shadows = {}
|
|||
end
|
|||
7f913647 | Marc Dequènes (Duck) | def load_global_config(extra_private_config_list = [])
|
|
1f9bfec2 | Marc Dequènes (Duck) | g_config_file = File.join(CFG_DIR, "global.conf")
|
|
unless File.exists? g_config_file
|
|||
raise PreProcessingError, _("Global LdapShadows config file is missing")
|
|||
end
|
|||
7f913647 | Marc Dequènes (Duck) | g_config_partial = YAML.load_file(g_config_file) || {}
|
|
extra_private_config_list += [
|
|||
1f9bfec2 | Marc Dequènes (Duck) | File.join(CFG_DIR, "global_private.conf")
|
|
]
|
|||
7f913647 | Marc Dequènes (Duck) | extra_private_config_list.each do |file|
|
|
1f9bfec2 | Marc Dequènes (Duck) | if File.exists?(file)
|
|
7f913647 | Marc Dequènes (Duck) | g_config_partial.merge!(YAML.load_file(file) || {})
|
|
1f9bfec2 | Marc Dequènes (Duck) | break
|
|
end
|
|||
end
|
|||
7f913647 | Marc Dequènes (Duck) | g_config = parse_and_validate('config', 'global', YAML.dump(g_config_partial))
|
|
1f9bfec2 | Marc Dequènes (Duck) | ||
ActiveLdap::Base.setup_connection(g_config[:ldap])
|
|||
@global_config = g_config
|
|||
end
|
|||
def global_config
|
|||
load_global_config() if @global_config.nil?
|
|||
@global_config
|
|||
end
|
|||
def load_shadow(shadow_name = nil)
|
|||
shadow_name = self.global_config[:default_shadow] if shadow_name.nil?
|
|||
if shadow_name.nil?
|
|||
raise PreProcessingError, _("Could not determine which Shadow to travel through")
|
|||
end
|
|||
shadow_config_path = File.join(CFG_DIR, "shadows", shadow_name)
|
|||
unless File.exists? shadow_config_path
|
|||
raise PreProcessingError, _("Configuration directory for Shadow '%s' is missing") % shadow_name
|
|||
end
|
|||
config_file = File.join(shadow_config_path, "shadow.conf")
|
|||
unless File.exists? config_file
|
|||
raise PreProcessingError, _("General configuration file for Shadow '%s' is missing") % shadow_name
|
|||
end
|
|||
7f913647 | Marc Dequènes (Duck) | config = File.read(config_file)
|
|
1f9bfec2 | Marc Dequènes (Duck) | ||
shadow = Shadow.new(shadow_name)
|
|||
a65fd5e8 | Marc Dequènes (Duck) | # register early (needed to load hooks)
|
|
@shadows[shadow_name] = {
|
|||
:config_path => shadow_config_path,
|
|||
:shadow => shadow
|
|||
}
|
|||
7f913647 | Marc Dequènes (Duck) | shadow.set_shadow_config(config)
|
|
1f9bfec2 | Marc Dequènes (Duck) | ||
load_config_components(shadow_config_path, 'aspects') do |c_name, c_config|
|
|||
shadow.add_aspect(c_name, c_config)
|
|||
end
|
|||
load_config_components(shadow_config_path, 'objects') do |c_name, c_config|
|
|||
4b046f91 | Marc Dequènes (Duck) | shadow.add_object(c_name, c_config)
|
|
1f9bfec2 | Marc Dequènes (Duck) | end
|
|
shadow.load_relations
|
|||
translation_path = File.join(shadow_config_path, "translations")
|
|||
if File.exists? translation_path
|
|||
# load interface translation
|
|||
I18n.load_path += Dir[File.join(translation_path, "**", "*.yml")]
|
|||
end
|
|||
shadow
|
|||
rescue
|
|||
raise PreProcessingError, _("Could not load shadow configuration: %s") % $!
|
|||
end
|
|||
def get_shadow_info(shadow_name)
|
|||
@shadows[shadow_name]
|
|||
end
|
|||
def parse_and_validate(def_name, type, def_data_raw)
|
|||
schema = load_schema(type)
|
|||
validator_klass = case type
|
|||
7f913647 | Marc Dequènes (Duck) | when 'global'
|
|
GlobalValidator
|
|||
1f9bfec2 | Marc Dequènes (Duck) | when 'object'
|
|
ObjectValidator
|
|||
when 'aspect'
|
|||
AspectValidator
|
|||
else
|
|||
Kwalify::Validator
|
|||
end
|
|||
validator = validator_klass.new(schema)
|
|||
# validate config with schema
|
|||
parser = Kwalify::Yaml::Parser.new(validator)
|
|||
def_data = parser.parse(def_data_raw, def_name)
|
|||
raise_if_validation_errors("#{type.capitalize} '#{def_name}'", parser.errors)
|
|||
def_data.recursive_symbolize_keys!
|
|||
end
|
|||
a65fd5e8 | Marc Dequènes (Duck) | def load_hook_content(shadow_name, type, hook_name)
|
|
s_info = get_shadow_info(shadow_name)
|
|||
return nil if s_info.nil?
|
|||
filename = File.join(s_info[:config_path], "hooks", type.pluralize, hook_name.to_s.downcase + ".rb")
|
|||
return nil unless File.exists?(filename)
|
|||
File.read(filename)
|
|||
end
|
|||
1f9bfec2 | Marc Dequènes (Duck) | protected
|
|
def load_config_components(shadow_config_path, type)
|
|||
c_config_dir = File.join(shadow_config_path, type)
|
|||
c_config_pattern = File.join(c_config_dir, "**", "*.conf")
|
|||
Dir.glob(c_config_pattern).each do |f|
|
|||
next if f[0..0] == "."
|
|||
c_name = File.basename(f).sub(".conf", "")
|
|||
c_config = File.read(f)
|
|||
yield(c_name, c_config)
|
|||
end
|
|||
end
|
|||
def load_schema(type)
|
|||
schema = @schemas[type]
|
|||
if schema.nil?
|
|||
schema_file = File.join(DATA_DIR, "schema", type + ".yaml")
|
|||
schema = YAML.load_file(schema_file)
|
|||
# validate schema
|
|||
metavalidator = Kwalify::MetaValidator.instance
|
|||
errors = metavalidator.validate(schema)
|
|||
raise_if_validation_errors("'#{type}' schema", errors)
|
|||
@schemas[type] = schema
|
|||
end
|
|||
schema
|
|||
rescue
|
|||
raise PreProcessingError, _("Could not load schema: %s") % $!
|
|||
end
|
|||
def raise_if_validation_errors(name, errors)
|
|||
if errors and not errors.empty?
|
|||
err_msg = []
|
|||
for e in errors
|
|||
err_msg << "[#{e.path}] #{e.message}"
|
|||
end
|
|||
raise PreProcessingError, _("%s is not valid:\n%s") % [name, err_msg.join("\n")]
|
|||
end
|
|||
end
|
|||
class LdapShadowsValidator < Kwalify::Validator
|
|||
## hook method called by Validator#validate()
|
|||
def validate_hook(value, rule, path, errors)
|
|||
msg_list = []
|
|||
validate_hook_in(value, rule, path, msg_list)
|
|||
msg_list.each do |msg|
|
|||
errors << Kwalify::ValidationError.new(msg, path)
|
|||
end
|
|||
end
|
|||
def validate_hook_relation(value, rule, path, msg_list)
|
|||
extra_params = [:type, :object]
|
|||
if value['type'] == 'belongs_to'
|
|||
7f913647 | Marc Dequènes (Duck) | ne_params = value.keys.collect{|k| k.to_sym } -
|
|
ActiveLdap::Associations::ClassMethods::VALID_BELONGS_TO_OPTIONS - extra_params
|
|||
1f9bfec2 | Marc Dequènes (Duck) | unless ne_params.empty?
|
|
msg_list << _("nonexisting relation mapping parameters (%s)") % ne_params.join(", ")
|
|||
end
|
|||
else
|
|||
7f913647 | Marc Dequènes (Duck) | ne_params = value.keys.collect{|k| k.to_sym } -
|
|
ActiveLdap::Associations::ClassMethods::VALID_HAS_MANY_OPTIONS - extra_params
|
|||
1f9bfec2 | Marc Dequènes (Duck) | unless ne_params.empty?
|
|
msg_list << _("nonexisting relation mapping parameters (%s)") % ne_params.join(", ")
|
|||
end
|
|||
end
|
|||
end
|
|||
end
|
|||
7f913647 | Marc Dequènes (Duck) | class GlobalValidator < LdapShadowsValidator
|
|
1f9bfec2 | Marc Dequènes (Duck) | def validate_hook_in(value, rule, path, msg_list)
|
|
case rule.name
|
|||
7f913647 | Marc Dequènes (Duck) | when 'LdapMapping'
|
|
ne_params = value.keys.collect{|k| k.to_sym } -
|
|||
ActiveLdap::Configuration::ClassMethods::CONNECTION_CONFIGURATION_KEYS -
|
|||
ActiveLdap::Adapter::Base::VALID_ADAPTER_CONFIGURATION_KEYS
|
|||
unless ne_params.empty?
|
|||
msg_list << _("nonexisting LDAP mapping parameters (%s)") % ne_params.join(", ")
|
|||
end
|
|||
1f9bfec2 | Marc Dequènes (Duck) | end
|
|
end
|
|||
end
|
|||
class ObjectValidator < LdapShadowsValidator
|
|||
def validate_hook_in(value, rule, path, msg_list)
|
|||
case rule.name
|
|||
7f913647 | Marc Dequènes (Duck) | when 'ObjectMapping'
|
|
ne_params = value.keys.collect{|k| k.to_sym } -
|
|||
ActiveLdap::Base::VALID_LDAP_MAPPING_OPTIONS
|
|||
1f9bfec2 | Marc Dequènes (Duck) | unless ne_params.empty?
|
|
7f913647 | Marc Dequènes (Duck) | msg_list << _("nonexisting object mapping parameters (%s)") % ne_params.join(", ")
|
|
1f9bfec2 | Marc Dequènes (Duck) | end
|
|
when 'RelationMapping'
|
|||
validate_hook_relation(value, rule, path, msg_list)
|
|||
end
|
|||
end
|
|||
end
|
|||
7f913647 | Marc Dequènes (Duck) | ||
class AspectValidator < LdapShadowsValidator
|
|||
def validate_hook_in(value, rule, path, msg_list)
|
|||
case rule.name
|
|||
when 'RelationMapping'
|
|||
validate_hook_relation(value, rule, path, msg_list)
|
|||
end
|
|||
end
|
|||
end
|
|||
1f9bfec2 | Marc Dequènes (Duck) | end
|
|
end
|