The current ldap_auth module in OpenNebula assumes that the username is the same as the LDAP dn entry. In more complex LDAP installations this is often not the case and LDAP authentication is a bit more complicated:
- Bind as a dedicated “search LDAP user”.
- Search the directory tree for the username.
- Get the DN from the search result.
- Bind as the DN with the user password.
I modified the current ldap_auth.rb to use this more complex process if the auth.conf file defines “search_filter” (if undefined it will use the original behavior and is thus backwards compatible). If defined, it expects “search_filter” to contain a suitable search string with “@@LOGIN@@” instead of the user name (to be replaced at runtime). E.g. something like: “(&(cn=@@LOGIN@@)(objectClass=user))”
It also expects the following config entries:
- sec_principal : the DN of the LDAP search user.
- sec_passwd: The password for the sec_principal.
- search_base: The base in the LDAP tree from which to search.
Code below (works with OpenNebula 2.0 and 2.2, but not with 3.0 beta):
[ruby]
# ————————————————————————–
# Copyright 2010, C12G Labs S.L., CSIRO
#
# This file is part of OpenNebula Ldap Authentication.
#
# OpenNebula Ldap Authentication 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 the hope
# That it will be useful, but (at your option) any later version.
#
# OpenNebula Ldap Authentication is distributed in 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 OpenNebula Ldap Authentication . If not, see http://www.gnu.org/licenses/
# ————————————————————————–
require ‘rubygems’
require ‘net/ldap’
# Ldap authentication module.
class LdapAuth
def initialize(config)
@config = config
end
def getLdap(user, password)
ldap = Net::LDAP.new
ldap.host = @config[:ldap][:host]
ldap.port = @config[:ldap][:port]
ldap.auth user, password
ldap
end
def getLdapDN(user)
search_filter = @config[:ldap][:search_filter]
if (search_filter.nil?)
return user
end
search_filter = search_filter.gsub(“@@LOGIN@@”, user)
ldap = getLdap(@config[:ldap][:sec_principal], @config[:ldap][:sec_passwd])
begin
ldap.search( :base => @config[:ldap][:search_base], :attributes => ‘dn’, :filter => search_filter, :return_result => true ) do |entry|
STDERR.puts “Found #{entry.dn}”
return entry.dn
end
rescue Exception => e
STDERR.puts “LDAP search failed: #{e.message}”
end
return nil
end
def auth(user_id, user, password, token)
dn = getLdapDN(user)
if(dn.nil?)
STDERR.puts(“User #{user} not found in LDAP”)
return false
end
begin
if getLdap(dn, token).bind
STDERR.puts “User #{user} authenticated!”
return true
end
rescue Exception => e
STDERR.puts “User authentication failed for #{entry.dn}: #{e.message}”
return false
end
STDERR.puts “User #{user} could not be authenticated.”
return false
end
end
[/ruby]
Carsten Friedrich wrote a blog post on how to extend OpenNebula’s LDAP authentication module