<?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>MrBlog &#187; openobject</title>
	<atom:link href="http://mrblog.nl/tag/openerp/feed" rel="self" type="application/rss+xml" />
	<link>http://mrblog.nl</link>
	<description>eliminating my ignorance one bit at a time</description>
	<lastBuildDate>Thu, 12 Jan 2012 09:54:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4-alpha-19847</generator>
	<atom:link rel='hub' href='http://mrblog.nl/?pushpress=hub'/>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/><atom:link rel='salmon' href='http://mrblog.nl/?salmon=endpoint'/><atom:link rel='http://salmon-protocol.org/ns/salmon-replies' href='http://mrblog.nl/?salmon=endpoint'/><atom:link rel='http://salmon-protocol.org/ns/salmon-mention' href='http://mrblog.nl/?salmon=endpoint'/>		<item>
		<title>OpenObject as LDAP data-source</title>
		<link>http://mrblog.nl/2009/09/29/openobject-as-ldap-data-source.html</link>
		<comments>http://mrblog.nl/2009/09/29/openobject-as-ldap-data-source.html#comments</comments>
		<pubDate>Tue, 29 Sep 2009 17:02:32 +0000</pubDate>
		<dc:creator>mrb</dc:creator>
				<category><![CDATA[integration]]></category>
		<category><![CDATA[claws]]></category>
		<category><![CDATA[openobject]]></category>

		<guid isPermaLink="false">http://mrblog.nl/?p=785</guid>
		<description><![CDATA[As a side-effect of Migrating to Claws I lost my OSX addressbook usage, at least for mail. In my company we use OpenERP for CRM, invoicing and other business needs. This means that the majority, if not all the email-addresses I need are in our OpenERP database. So, it made sense to finish an effort [...]]]></description>
			<content:encoded><![CDATA[<p>As a side-effect of <a href="http://mrblog.nl/2009/09/18/a-weeks-worth-of-claws-mail-on-osx.html">Migrating to <a href='http://claws-mail.org' rel='external ' title='Claws email client'>Claws</a></a> I lost my OSX addressbook usage, at least for mail. In my company we use <a href="http://openerp.com"><a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a></a> for CRM, invoicing and other business needs. This means that the majority, if not all the email-addresses I need are in our <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> database. </p>

<p>So, it made sense to finish an effort I started earlier, which is to link <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> to our LDAP server and thus be able to query information from the <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> database through an LDAP interface and have every address available in the <a href='http://claws-mail.org' rel='external ' title='Claws email client'>Claws</a> addressbook (and the OSX addressbook too for that matter). </p>

<p>In an earlier version of <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> we used a specific module for this, which basically published an LDAP entry whenever we changed data in the <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> database. This worked, but was a less than ideal solution, not to mention it stopped working on an <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> upgrade. The solution I wanted was to have the data available in LDAP immediately. This meant making the LDAP server a &#8220;client&#8221; of the <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> database or, said another way, making the <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> database function as an SQL backend to the LDAP server.</p>

<h4>Defining an SQL backend for LDAP</h4>

<p>Creating an SQL backend for slapd is, albeit terse, documented. I mainly used the information at <a href="http://www.openldap.org/faq/data/cache/978.html">the OpenLDAP FAQ</a>. The basic idea is that the LDAP-server connects through ODBC to the database, the <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> database in our case, and translates information found in relational tables to a subtree of the LDAP hierarchy.</p>

<p>To model this information, you have to create at least 3 tables in the database:</p>

<ol>
<li><code>ldap_oc_mappings</code>: which objectClass of LDAP is stored in what table;</li>
<li><code>ldap_attr_mappings</code>: how attributeTypes of an objectClass are resolved from RDBMS data;</li>
<li><code>ldap_entries</code>: what&#8217;s the DN of an entry, and how the entry relates to its objectClass mapping and to its parent DN;</li>
</ol>

<p>The FAQ mentions two other tables, which we do not need. The idea is to specify in these three tables how the LDAP server gets to the entries and what they mean. For addressbook-like entries for mail, the defacto objectClass to use for this is something referred to an &#8216;inetOrgPerson&#8217;. The collection of these objects will be below an objectClass &#8216;organizationalUnit&#8217;, giving the simplest &#8216;tree-relation&#8217;we can think of.</p>

<h4>Making the SQL backend use <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a></h4>

<p>The table <code>ldap_oc-mappings</code> is queried by the LDAP server to map these object classes to tables, so the server knows in which tables to look for the attributes of these two classes. The next two statements insert two rows in that table, one for each object Class, mapping them to the tables <code>ldap_inetOrgPerson</code> and <code>ldap_organizationalUnit</code>, expecting a column <code>id</code> to contain the primary key for the objects.</p>

<pre><code class="prettyprint">INSERT INTO ldap_oc_mappings(name,keytbl,keycol) 
    VALUES('inetOrgPerson','ldap_inetOrgPerson','id');
INSERT INTO ldap_oc_mappings(name,keytbl,keycol) 
    VALUES('organizationalUnit','ldap_ organizationalUnit','id');
</code></pre>

<p>The <code>ldap_inetOrgPerson</code> is actually a view over the <code>res_partner_address</code> table in <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a>, so it uses the data directly. </p>

<pre><code class="prettyprint">CREATE OR REPLACE VIEW ldap_inetorgperson AS 
  SELECT 
    a.id, 
    btrim((COALESCE(a.firstname,'')||' ') || a.lastname) AS cn, 
    btrim((COALESCE(a.firstname,'')||' ') || a.lastname) AS displayname, 
    a.phone AS telephonenumber, 
    a.lastname AS sn, 
    a.firstname AS givenname, 
    a.fax AS facsimiletelephonenumber, 
    a.mobile, 
    a.private_phone AS homephone, 
    lower(a.email) AS mail, 
    a.street, 
    a.zip AS postalcode
  FROM res_partner_address a
  WHERE 
    a.email  ''  AND 
    a.email  '"' AND 
    a.type  =  'contact';
</code></pre>

<p>This gives a dataset of all people who actually have an email-address registered in the <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> database. The column aliases are not needed as such, but make the construction of the <code>ldap_attr_mappings</code> table a bit easier. The second objectClass we registered in <code>ldap_oc_mappings</code>, <code>organizationalUnit</code> can be modelled with one simple row in the table <code>ldap_organizationalUnit</code>:</p>

<pre><code class="prettyprint">INSERT INTO ldap_organizationalUnit(name) VALUES ('addressbook');
</code></pre>

<p>With that row, we basically define one organizational unit in our simple tree named <code>addressbook</code> under which all our objects of type <code>inetOrgPerson</code> will be placed. </p>

<p>So, at this point we have 2 objectClasses registered, we have created the raw data for them. What&#8217;s left? Two things, first, we need to define how the attributes of the raw data relate to the object attributes. For this, the table <code>ldap_attr_mappings</code> contains a row for each attribute. For the <code>telephoneNumber</code> attribute, the data row is as follows:</p>

<pre><code class="prettyprint">INSERT INTO ldap_attr_mappings(
        oc_map_id,name,sel_expr,from_tbls,join_where
    ) 
VALUES(
    1,'telephoneNumber','telephoneNumber','ldap_inetOrgPerson','1=1'
);
</code></pre>

<p>This says basically to the ldap server that in order to get to the <code>telephoneNumber</code> attribute for <code>inetOrgPerson</code> (<code>oc_map_id</code> 1 refers to the first row in the <code>ldap_oc_mappings</code> table), it needs to look in the table <code>ldap_inetOrgPerson</code>, use the same attribute name for the column and apply no special where clause. It is basically a recipe for the server to translate an LDAP request into an SQL query. </p>

<p>For each of the columns in the <code>ldap_inetOrgPerson</code> view, such a row needs to be present in the <code>ldap_attr_mappings</code> table.</p>

<p>Still here? The final step is to create the third meta table <code>ldap_entries</code>. This table is basically the lookup table to map <em>ldap-index values</em> to <em>rdbms-index values</em>.  I have defined <code>ldap_entries</code> as a view on the raw data as follows:</p>

<pre><code class="prettyprint"> CREATE OR REPLACE VIEW ldap_entries AS 
   SELECT 
     0 AS id, 
     'ou=addressbook,dc=hsdev,dc=com' AS dn, 
     2 AS oc_map_id, 
     0 AS parent, 
     0 AS keyval
    UNION 
   SELECT 
     ldap_inetorgperson.id, 
     ('cn=' || ldap_inetorgperson.cn) || 
     ',ou=addressbook,dc=hsdev,dc=com' AS dn, 
     1 AS oc_map_id, 
     0 AS parent, 
     ldap_inetorgperson.id AS keyval
   FROM ldap_inetorgperson;
</code></pre>

<p>This does 2 things, it refers the ldap addres <code>ou=addressbook,dc=hsdev,dc=com</code> as the organizational unit (<code>oc_map_id</code> = 2) and assigns that ID 0. The second part of the UNION then formats each of the inetOrgPerson addresses as an LDAP address in the constructed tree (mine would be: <code>cn=Marcel van der Boom,ou=addressbook,dc=hsdev,dc=com</code>) and maps it to the ID in the raw data table (<code>keyval</code>) and puts the organizational unit as its parent.</p>

<p>With the above a minimal <em>proof of concept</em> can be constructed so that each partner address which has an email-address shows up in LDAP. After this, it&#8217;s a matter of configuring the email-client using the <code>ou=addressbook,dc=hsdev,dc=com</code> as a search base.</p>

<p>Here&#8217;s a picture of my record in the claws address book:</p>

<p style="text-align: center"><a href="http://mrblog.nl/files/2009/09/screen_011.png" target="_blank"><img src="http://mrblog.nl/files/2009/09/screen_011.png" width="500px" alt="screen_011.png" /></a>
</p>

<p>The same concept can be applied to other data in <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> (the partner records themselves come to mind or user accounts). It would not be that hard to wrap the above into an <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> module to manage this. Once the LDAP server has a configuration to use an SQL backend, all configuration can be done in <a href='http://openerp.com' rel='external ' title='Open Source ERP and application framework'>OpenERP</a> itself, modelling access using the meta tables. Perhaps I&#8217;ll do that at some point, if some of my customers would benefit from this too.</p>
]]></content:encoded>
			<wfw:commentRss>http://mrblog.nl/2009/09/29/openobject-as-ldap-data-source.html/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
	</channel>
</rss>

