diff --git a/src/authm_mad/remotes/ldap/authenticate b/src/authm_mad/remotes/ldap/authenticate index 8a01485974..95ec7cf4d9 100755 --- a/src/authm_mad/remotes/ldap/authenticate +++ b/src/authm_mad/remotes/ldap/authenticate @@ -83,9 +83,21 @@ begin end if ldap.authenticate(user_name, secret) + groups = ldap.get_groups + if groups.empty? + if !server_conf[:mapping_default] + STDERR.puts "User does not belong to a mapped group" + authenticated = false + break + else + groups = [server_conf[:mapping_default]] + end + end + + group_list = groups.join(' ') escaped_user=URI_PARSER.escape(user) escaped_secret=URI_PARSER.escape(user_name) - puts "ldap #{escaped_user} #{escaped_secret}" + puts "ldap #{escaped_user} #{escaped_secret} #{group_list}" authenticated=true break else diff --git a/src/authm_mad/remotes/ldap/ldap_auth.conf b/src/authm_mad/remotes/ldap/ldap_auth.conf index f4241781f5..066eb7280b 100644 --- a/src/authm_mad/remotes/ldap/ldap_auth.conf +++ b/src/authm_mad/remotes/ldap/ldap_auth.conf @@ -49,6 +49,21 @@ server 1: # user field that that is in in the group group_field, if not set 'dn' will be used #:user_group_field: 'dn' + # Generate mapping file from group template info + :mapping_generate: true + + # Seconds a mapping file remain untouched until the next regeneration + :mapping_timeout: 300 + + # Name of the mapping file in OpenNebula var diretory + :mapping_filename: server1.yaml + + # Key from the OpenNebula template to map to an AD group + :mapping_key: GROUP_DN + + # Default group ID used for users in an AD group not mapped + :mapping_default: 1 + # this example server wont be called as it is not in the :order list server 2: :auth_method: :simple diff --git a/src/authm_mad/remotes/ldap/ldap_auth.rb b/src/authm_mad/remotes/ldap/ldap_auth.rb index 5c6345a59e..161ef225ea 100644 --- a/src/authm_mad/remotes/ldap/ldap_auth.rb +++ b/src/authm_mad/remotes/ldap/ldap_auth.rb @@ -15,22 +15,39 @@ # ---------------------------------------------------------------------------- # require 'rubygems' +require 'opennebula' require 'net/ldap' +require 'yaml' + +if !defined?(ONE_LOCATION) + ONE_LOCATION=ENV["ONE_LOCATION"] +end + +if !ONE_LOCATION + VAR_LOCATION="/var/lib/one/" +else + VAR_LOCATION=ONE_LOCATION+"/var/" +end module OpenNebula; end class OpenNebula::LdapAuth def initialize(options) @options={ - :host => 'localhost', - :port => 389, - :user => nil, - :password => nil, - :base => nil, - :auth_method => :simple, - :user_field => 'cn', - :user_group_field => 'dn', - :group_field => 'member' + :host => 'localhost', + :port => 389, + :user => nil, + :password => nil, + :base => nil, + :auth_method => :simple, + :user_field => 'cn', + :user_group_field => 'dn', + :group_field => 'member', + :mapping_generate => true, + :mapping_timeout => 300, + :mapping_filename => 'server1.yaml', + :mapping_key => 'GROUP_DN', + :mapping_default => 1 }.merge(options) ops={} @@ -47,9 +64,61 @@ class OpenNebula::LdapAuth ops[:port]=@options[:port].to_i if @options[:port] ops[:encryption]=@options[:encryption] if @options[:encryption] + @options[:mapping_file_path] = VAR_LOCATION + @options[:mapping_filename] + generate_mapping if @options[:mapping_generate] + load_mapping + @ldap=Net::LDAP.new(ops) end + def generate_mapping + file=@options[:mapping_file_path] + generate = false + + if File.exists?(file) + stat = File.stat(file) + age = Time.now.to_i - stat.mtime.to_i + generate = true if age > @options[:mapping_timeout] + else + generate = true + end + + return if !generate + + client = OpenNebula::Client.new + group_pool = OpenNebula::GroupPool.new(client) + group_pool.info + + groups = group_pool.to_hash[''] + groups=[group_pool.get_hash['GROUP_POOL']['GROUP']].flatten + + yaml={} + + groups.each do |group| + if group['TEMPLATE'] && group['TEMPLATE'][@options[:mapping_key]] + yaml[group['TEMPLATE'][@options[:mapping_key]]] = group['ID'] + end + end + + File.open(file, 'w') do |f| + f.write(yaml.to_yaml) + end + end + + def load_mapping + file=@options[:mapping_file_path] + + @mapping = {} + + if File.exists?(file) + @mapping = YAML.load(File.read(file)) + end + + if @mapping.class != Hash + @mapping = {} + end + end + def find_user(name) begin result=@ldap.search( @@ -57,12 +126,14 @@ class OpenNebula::LdapAuth :filter => "#{@options[:user_field]}=#{name}") if result && result.first - [result.first.dn, result.first[@options[:user_group_field]]] + @user = result.first + [@user.dn, @user[@options[:user_group_field]]] else result=@ldap.search(:base => name) if result && result.first - [name, result.first[@options[:user_group_field]]] + @user = result.first + [name, @user[@options[:user_group_field]]] else [nil, nil] end @@ -99,5 +170,20 @@ class OpenNebula::LdapAuth false end end + + def get_groups + groups = [] + + [@user['memberOf']].flatten.each do |group| + if @mapping[group] + groups << @mapping[group] + else + groups << @options[:mapping_default] + end + end + + groups.delete(false) + groups.compact + end end