<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">

<head>
<meta http-equiv=Content-Type content="text/html; charset=us-ascii">
<meta name=Generator content="Microsoft Word 12 (filtered medium)">
<style>
<!--
 /* Font Definitions */
 @font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
-->
</style>
<!--[if gte mso 9]><xml>
 <o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
 <o:shapelayout v:ext="edit">
  <o:idmap v:ext="edit" data="1" />
 </o:shapelayout></xml><![endif]-->
</head>

<body lang=EN-AU link=blue vlink=purple>

<div class=WordSection1>

<p class=MsoNormal><span lang=EN-US>The current ldap_auth module is assuming
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:<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US>* Bind as a dedicated “search LDAP
user”<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>* Search the directory tree for the
username<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>* Get the DN from the search result<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>* Bind as the DN with the user password<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US> I modified the current ldap_auth.rb
to use this more complex process if the auth.conf file defines “search_filter”.
In this case 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))”<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US>It also expects the following config
entries:<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>* sec_principal : the DN of the LDAP search
user.<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>* sec_passwd: The password for the
sec_principal<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>* search_base: The base in the LDAP tree
from which to search<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US>Code below:<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US>#
--------------------------------------------------------------------------<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># Copyright 2010, C12G Labs S.L., CSIRO<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>#<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># This file is part of OpenNebula Ldap
Authentication.<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>#<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># OpenNebula Ldap Authentication is free
software: you can redistribute it and/or modify<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># it under the terms of the GNU General
Public License as published by<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># the Free Software Foundation, either
version 3 of the License, or the hope<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># That it will be useful, but (at your
option) any later version.<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>#<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># OpenNebula Ldap Authentication is
distributed in WITHOUT ANY WARRANTY; without even<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># PURPOSE.  See the GNU General Public
License for more details.<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>#<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># You should have received a copy of the
GNU General Public License<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US># along with OpenNebula Ldap Authentication
. If not, see <http://www.gnu.org/licenses/><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>#
--------------------------------------------------------------------------<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>require 'rubygems'<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US>require 'net/ldap'<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US># Ldap authentication module.<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US>class LdapAuth<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    def initialize(config)<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
@config = config<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    def getLdap(user,
password)  <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      ldap =
Net::LDAP.new<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      ldap.host =
@config[:ldap][:host]<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      ldap.port =
@config[:ldap][:port]<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      ldap.auth
user, password<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      ldap<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    def getLdapDN(user) <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>     
search_filter = @config[:ldap][:search_filter]<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      if
(search_filter.nil?)<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
return user<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>     
search_filter = search_filter.gsub("@@LOGIN@@", user)<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      ldap =
getLdap(@config[:ldap][:sec_principal], @config[:ldap][:sec_passwd])<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      begin<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
ldap.search( :base => @config[:ldap][:search_base], :attributes => 'dn', <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>                   
 :filter => search_filter, :return_result => true ) do |entry|<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>         
STDERR.puts "Found #{entry.dn}"<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>         
return entry.dn<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      rescue
Exception => e  <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
STDERR.puts "LDAP search failed: #{e.message}"<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      return nil<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    def auth(user_id, user,
password, token)<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      dn =
getLdapDN(user)<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      if(dn.nil?)<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
STDERR.puts("User #{user} not found in LDAP")<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
return false<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      begin <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
if getLdap(dn, token).bind<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>         
STDERR.puts "User #{user} authenticated!"<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>         
return true<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      rescue 
Exception => e  <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
STDERR.puts "User authentication failed for #{entry.dn}:
#{e.message}"<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>       
return false<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      <o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      STDERR.puts
"User #{user} could not be authenticated."<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>      return false<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>    end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US>  end<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>

</div>

</body>

</html>