<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Live &#38; Code &#187; authlogic</title>
	<atom:link href="http://www.liveandcode.com/tag/authlogic/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.liveandcode.com</link>
	<description>Enrico on programming, living, and everything in between</description>
	<lastBuildDate>Mon, 27 Jun 2011 01:10:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>LDAP Pass-through Authentication with Authlogic and ActiveLdap</title>
		<link>http://www.liveandcode.com/2009/08/30/ldap-pass-through-authentication-with-authlogic-and-activeldap/</link>
		<comments>http://www.liveandcode.com/2009/08/30/ldap-pass-through-authentication-with-authlogic-and-activeldap/#comments</comments>
		<pubDate>Sun, 30 Aug 2009 17:57:47 +0000</pubDate>
		<dc:creator>Enrico</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[authlogic]]></category>
		<category><![CDATA[identity management]]></category>
		<category><![CDATA[ldap]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.liveandcode.com/?p=195</guid>
		<description><![CDATA[Today, I pushed a branch to my fork of authlogic_example: with-activeldap. This branch shows a way of implementing pass-through authentication to an LDAP server using ActiveLdap and Authlogic, with just some small changes to the User and UserSession models. First, we&#8217;ll need to bring in the net-ldap and activeldap gems. We edit config/environment.rb to include [...]]]></description>
			<content:encoded><![CDATA[<p>Today, I pushed a branch to my fork of <code>authlogic_example</code>: <a title="enricob's authlogic_example at with-activeldap - GitHub" href="http://github.com/enricob/authlogic_example/tree/with-activeldap"><code>with-activeldap</code></a>.</p>
<p>This branch shows a way of implementing pass-through authentication to an LDAP server using <a title="RubyForge: Ruby/ActiveLdap Project Page" href="http://rubyforge.org/projects/ruby-activeldap/">ActiveLdap</a> and <a title="binarylogic's authlogic at master - GitHub" href="http://github.com/binarylogic/authlogic">Authlogic</a>, with just some small changes to the <code>User</code> and <code>UserSession</code> models.</p>
<p><span id="more-195"></span><br />
First, we&#8217;ll need to bring in the <code>net-ldap</code> and <code>activeldap</code> gems. We edit <code>config/environment.rb</code> to include the following two lines:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">config.<span style="color:#9900CC;">gem</span> <span style="color:#996600;">&quot;net-ldap&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:lib</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span>, <span style="color:#ff3333; font-weight:bold;">:version</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'&gt;=0.0.5'</span>
config.<span style="color:#9900CC;">gem</span> <span style="color:#996600;">&quot;activeldap&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:lib</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;active_ldap&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:version</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'1.0.9'</span></pre></div></div>

<p>If you use <code>sudo gem install net-ldap</code>, you&#8217;ll get 0.0.4. Here, I&#8217;ve built the 0.0.5 gem from the <a title="innovationfactory's ruby-net-ldap at master - GitHub" href="http://github.com/innovationfactory/ruby-net-ldap/">GitHub repo</a>. This is because there are some bug fixes in the GitHub master that aren&#8217;t in the RubyForge gem. In the <code>with-activeldap</code> branch, the two gems are vendored.</p>
<p>Now, we create config/ldap.yml to configure ActiveLdap&#8217;s connection to our LDAP server. Here&#8217;s mine:</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;">development:
  host: 127.0.0.1
  base: dc=dev,dc=Asuka,dc=local
  bind_dn: cn=Manager,dc=dev,dc=Asuka,dc=local
  password: secret
&nbsp;
test:
  host: 127.0.0.1
  base: dc=test,dc=Asuka,dc=local
  bind_dn: cn=Manager,dc=Asuka,dc=local
  password: secret
&nbsp;
production:
  host: 127.0.0.1
  base: dc=prod,dc=Asuka,dc=local
  bind_dn: cn=Manager,dc=Asuka,dc=local
  password: secret</pre></div></div>

<p>This tells ActiveLdap the server/port to connect to, what the base entry for our LDAP objects is, and what user to bind as for operations on the server. Now, we create a <code>LdapUser</code> class to represent user entries in the LDAP:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> LdapUser <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveLdap::Base</span>
  ldap_mapping <span style="color:#ff3333; font-weight:bold;">:dn_attribute</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;uid&quot;</span>,
    <span style="color:#ff3333; font-weight:bold;">:scope</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> :<span style="color:#CC0066; font-weight:bold;">sub</span>,
    <span style="color:#ff3333; font-weight:bold;">:prefix</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;o=users&quot;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>This defines an LDAP user as being an entry from the <code>o=users</code> organization, where all of the entries are distinguished by the <code>uid</code> attribute. Now, we should be able to use the console to list all of our LDAP users like so:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"> <span style="color:#006600; font-weight:bold;">&gt;&gt;</span> LdapUser.<span style="color:#9900CC;">all</span></pre></div></div>

<p>Now, we&#8217;ll add some methods to the <code>User</code> model that allow us to look up users by login in the LDAP and create entries in the database if they don&#8217;t already exist. We&#8217;ll also need a method for forwarding the credentials provided on the login form to the LDAP and see if they are valid:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> User <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  acts_as_authentic <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>c<span style="color:#006600; font-weight:bold;">|</span>
    <span style="color:#008000; font-style:italic;"># Don't validate password, since that will be held in the LDAP</span>
    c.<span style="color:#9900CC;">validate_password_field</span> = <span style="color:#0000FF; font-weight:bold;">false</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> ldap_entry
    LdapUser.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">login</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># Tries to find a User first by looking into the database and then by</span>
  <span style="color:#008000; font-style:italic;"># creating a User if there's an LDAP entry for the given login</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">find_or_create_from_ldap</span><span style="color:#006600; font-weight:bold;">&#40;</span>login<span style="color:#006600; font-weight:bold;">&#41;</span>
    find_by_login<span style="color:#006600; font-weight:bold;">&#40;</span>login<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">||</span> create_from_ldap_if_valid<span style="color:#006600; font-weight:bold;">&#40;</span>login<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># Creates a User record in the database if there is an entry in the LDAP</span>
  <span style="color:#008000; font-style:italic;"># with the given login</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">create_from_ldap_if_valid</span><span style="color:#006600; font-weight:bold;">&#40;</span>login<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">begin</span>
      User.<span style="color:#9900CC;">create</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:login</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> login<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> LdapUser.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>login<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">rescue</span> <span style="color:#6666ff; font-weight:bold;">ActiveLdap::EntryNotFound</span>
      <span style="color:#0000FF; font-weight:bold;">nil</span> <span style="color:#008000; font-style:italic;"># Don't do anything since we can't find an entry</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  protected
    <span style="color:#008000; font-style:italic;"># Authenticates the user against the LDAP.</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> valid_ldap_credentials?<span style="color:#006600; font-weight:bold;">&#40;</span>password_plaintext<span style="color:#006600; font-weight:bold;">&#41;</span>
      ldap_entry.<span style="color:#9900CC;">bind</span><span style="color:#006600; font-weight:bold;">&#40;</span>password_plaintext<span style="color:#006600; font-weight:bold;">&#41;</span>
      ldap_entry.<span style="color:#9900CC;">remove_connection</span>
      <span style="color:#0000FF; font-weight:bold;">true</span>
    <span style="color:#9966CC; font-weight:bold;">rescue</span> <span style="color:#6666ff; font-weight:bold;">ActiveLdap::AuthenticationError</span>, <span style="color:#6666ff; font-weight:bold;">ActiveLdap::LdapError::UnwillingToPerform</span>
      <span style="color:#0000FF; font-weight:bold;">false</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>With this, there is no longer a need for the <code>crypted_password</code> and <code>password_salt</code> columns in the <code>users</code> table, so if those columns exist, you&#8217;ll have to write a migration to remove them (or at least allow NULL values for them). Now, we modify the <code>UserSession</code> to use our custom methods for looking up users and validating their credentials:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> UserSession <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">Authlogic::Session::Base</span>
  find_by_login_method <span style="color:#ff3333; font-weight:bold;">:find_or_create_from_ldap</span>
  verify_password_method <span style="color:#ff3333; font-weight:bold;">:valid_ldap_credentials</span>?
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>With that, we should now be able to log in as a user by providing her <code>uid</code> as the login and the password. LDAP pass-through authentication achieved! There is a downside though: ActiveLdap is not particularly efficient with its queries but this can be mitigated by storing the user&#8217;s LDAP entry (the <code>LdapUser</code> object) in the <code>User</code> instance when it is first looked up.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">def</span> ldap_entry
  <span style="color:#0066ff; font-weight:bold;">@ldap_entry</span> <span style="color:#006600; font-weight:bold;">||</span>= LdapUser.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">login</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>In a future post, I will extend this further by modeling LDAP groups and bringing in declarative_authorization to implement role-based access control based on LDAP group membership.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.liveandcode.com/2009/08/30/ldap-pass-through-authentication-with-authlogic-and-activeldap/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>

