Project

General

Profile

Download (10 KB) Statistics
| Branch: | Tag: | Revision:
1f9bfec2 Marc Dequènes (Duck)
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
bc2c2691 Marc Dequènes (Duck)
# Copyright (c) 2009-2010 Marc Dequènes (Duck) <Duck@DuckCorp.org>
1f9bfec2 Marc Dequènes (Duck)
#
# 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'
6d235fb6 Marc Dequènes (Duck)
require 'ldap_shadows/shadow'
1f9bfec2 Marc Dequènes (Duck)
require 'singleton'
7f913647 Marc Dequènes (Duck)
require 'yaml'
1f9bfec2 Marc Dequènes (Duck)
require 'kwalify'
9a7f1b63 Marc Dequènes (Duck)
require 'facets/hash/recursive_merge'
1f9bfec2 Marc Dequènes (Duck)
module LdapShadows
class Config
include Singleton

def initialize
@global_config = nil
5174b503 Marc Dequènes (Duck)
@world_config = nil
1f9bfec2 Marc Dequènes (Duck)
@schemas = {}
9a7f1b63 Marc Dequènes (Duck)
@default_configs = {}
1f9bfec2 Marc Dequènes (Duck)
@shadows = {}
end

5174b503 Marc Dequènes (Duck)
def load_global_config
9a7f1b63 Marc Dequènes (Duck)
g_default_config = load_default_config('global')

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

9a7f1b63 Marc Dequènes (Duck)
g_def_partial = YAML.load_file(g_config_file) || {}
5174b503 Marc Dequènes (Duck)
g_def = parse('config', 'global', YAML.dump(g_def_partial))
g_config = g_default_config.recursive_merge(g_def)

@global_config = g_config
end

def load_world_config(world_name = nil, extra_private_config_list = [])
world_name = self.global_config[:default_world] if world_name.nil?

w_default_config = load_default_config('world')

w_config_path = File.join(CFG_DIR, "worlds", world_name)

w_config_file = File.join(w_config_path, "world.conf")
unless File.exists? w_config_file
raise PreProcessingError, _("General configuration file for World '%s' is missing") % world_name
end

w_def_partial = YAML.load_file(w_config_file) || {}
7f913647 Marc Dequènes (Duck)
extra_private_config_list += [
5174b503 Marc Dequènes (Duck)
File.join(w_config_path, "world_private.conf")
1f9bfec2 Marc Dequènes (Duck)
]
7f913647 Marc Dequènes (Duck)
extra_private_config_list.each do |file|
1f9bfec2 Marc Dequènes (Duck)
if File.exists?(file)
5174b503 Marc Dequènes (Duck)
w_def_partial.merge!(YAML.load_file(file) || {})
1f9bfec2 Marc Dequènes (Duck)
break
end
end
5174b503 Marc Dequènes (Duck)
w_def = parse('config', 'world', YAML.dump(w_def_partial))
w_config = w_default_config.recursive_merge(w_def)
1f9bfec2 Marc Dequènes (Duck)
5174b503 Marc Dequènes (Duck)
ActiveLdap::Base.setup_connection(w_config[:ldap])
1f9bfec2 Marc Dequènes (Duck)
5174b503 Marc Dequènes (Duck)
@world_config = w_config
@world_config_path = w_config_path
1f9bfec2 Marc Dequènes (Duck)
end

def global_config
load_global_config() if @global_config.nil?
@global_config
end

5174b503 Marc Dequènes (Duck)
def world_config
load_world_config() if @world_config.nil?
@world_config
end

1f9bfec2 Marc Dequènes (Duck)
def load_shadow(shadow_name = nil)
5174b503 Marc Dequènes (Duck)
shadow_name = self.world_config[:default_shadow] if shadow_name.nil?
1f9bfec2 Marc Dequènes (Duck)
if shadow_name.nil?
raise PreProcessingError, _("Could not determine which Shadow to travel through")
end

5174b503 Marc Dequènes (Duck)
shadow_config_path = File.join(@world_config_path, "shadows", shadow_name)
1f9bfec2 Marc Dequènes (Duck)
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)
b527ce77 Marc Dequènes (Duck)
shadow = Shadow.new(shadow_name, self)
953a2b4d Marc Dequènes (Duck)
# register early (needed to load plugins)
a65fd5e8 Marc Dequènes (Duck)
@shadows[shadow_name] = {
:config_path => shadow_config_path,
:shadow => shadow
}
bbe89518 Marc Dequènes (Duck)
shadow.set_config(config)
1f9bfec2 Marc Dequènes (Duck)
2cb97830 Marc Dequènes (Duck)
include_path = File.join(shadow_config_path, "plugins", "includes")
$:.unshift(include_path) if File.directory?(include_path)

9a7f1b63 Marc Dequènes (Duck)
load_element_config(shadow_config_path, 'aspects') do |c_name, c_config|
1f9bfec2 Marc Dequènes (Duck)
shadow.add_aspect(c_name, c_config)
end

9a7f1b63 Marc Dequènes (Duck)
load_element_config(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

90809ae4 Marc Dequènes (Duck)
shadow.cast
1f9bfec2 Marc Dequènes (Duck)
90809ae4 Marc Dequènes (Duck)
# TODO: find a way to handle translations per-shadow
1f9bfec2 Marc Dequènes (Duck)
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

428fdd46 Marc Dequènes (Duck)
def parse(def_name, type, def_data_raw, validate = true, extra_data = nil)
1f9bfec2 Marc Dequènes (Duck)
schema = load_schema(type)

9a7f1b63 Marc Dequènes (Duck)
if validate
validator_klass = case type
5174b503 Marc Dequènes (Duck)
when 'world'
WorldValidator
9a7f1b63 Marc Dequènes (Duck)
when 'object'
ObjectValidator
when 'aspect'
AspectValidator
else
428fdd46 Marc Dequènes (Duck)
LdapShadowsValidator
9a7f1b63 Marc Dequènes (Duck)
end
validator = validator_klass.new(schema)
428fdd46 Marc Dequènes (Duck)
validator.extra_data = extra_data
1f9bfec2 Marc Dequènes (Duck)
else
9a7f1b63 Marc Dequènes (Duck)
validator = nil
1f9bfec2 Marc Dequènes (Duck)
end

# 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

9a7f1b63 Marc Dequènes (Duck)
def load_default_config(type)
default_config = @default_configs[type]
if default_config.nil?
filename = File.join(DATA_DIR, "default_config", type + ".yaml")
default_config_raw = File.read(filename)
default_config = parse(':defaults:', type, default_config_raw, false)

@default_configs[type] = default_config
end
default_config
rescue
raise PreProcessingError, _("Could not load default config for '%s': %s") % [type, $!]
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?

953a2b4d Marc Dequènes (Duck)
filename = File.join(s_info[:config_path], "plugins", type.pluralize, hook_name.to_s.downcase + ".rb")
a65fd5e8 Marc Dequènes (Duck)
return nil unless File.exists?(filename)

File.read(filename)
end

9a7f1b63 Marc Dequènes (Duck)
def load_element_config(shadow_config_path, type)
1f9bfec2 Marc Dequènes (Duck)
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
9a7f1b63 Marc Dequènes (Duck)
raise PreProcessingError, _("Could not load schema for '%s': %s") % [type, $!]
1f9bfec2 Marc Dequènes (Duck)
end

9a7f1b63 Marc Dequènes (Duck)
protected

1f9bfec2 Marc Dequènes (Duck)
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
428fdd46 Marc Dequènes (Duck)
attr_accessor :extra_data

1f9bfec2 Marc Dequènes (Duck)
## 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

428fdd46 Marc Dequènes (Duck)
def validate_hook_in(value, rule, path, msg_list)
end

1f9bfec2 Marc Dequènes (Duck)
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

5174b503 Marc Dequènes (Duck)
class WorldValidator < 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 } -
428fdd46 Marc Dequènes (Duck)
ActiveLdap::Base::VALID_LDAP_MAPPING_OPTIONS -
@extra_data[:default_parameters][:mapping].keys
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