<?xml version="1.0" encoding="UTF-8"?> <chapter annotations="slide" version="5.1" xml:id="sdiLdap" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xila="http://www.w3.org/2001/XInclude/local-attributes" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns="http://docbook.org/ns/transclusion" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:db="http://docbook.org/ns/docbook"> <title><xref linkend="glo_LDAP"/></title> <figure xml:id="sdi_ldap_readings"> <title>Recommended readings</title> <itemizedlist> <listitem> <para><uri xlink:href="http://www.zytrax.com/books/ldap">LDAP for Rocket Scientists</uri></para> </listitem> <listitem> <para><uri xlink:href="https://www.novell.com/coolsolutions/feature/15359.html">An Introduction to LDAP: Part 1</uri></para> </listitem> <listitem> <para><uri xlink:href="http://quark.humbug.org.au/publications/ldap/ldap_tut.html">Introduction to LDAP</uri></para> </listitem> <listitem> <para><uri xlink:href="http://ldapman.org/articles/intro_to_ldap.html">ldapman.org, An Introduction to LDAP</uri></para> </listitem> </itemizedlist> </figure> <figure xml:id="sdi_ldap_opendapDoc"> <title><productname>Openldap</productname> server documentation</title> <para>Exercises are based on the <uri xlink:href="http://www.openldap.org">OpenLDAP</uri> server implementation.</para> <para>Related material at <uri xlink:href="http://www.openldap.org">http://www.openldap.org</uri>.</para> </figure> <figure xml:id="sdi_ldap_whatIsLdap"> <title>What is LDAP anyway?</title> <itemizedlist> <listitem> <para><emphasis role="red">L</emphasis>ightweight <emphasis role="red">D</emphasis>irectory <emphasis role="red">A</emphasis>ccess <emphasis role="red">P</emphasis>rotocol</para> </listitem> <listitem> <para>Vendor independent</para> </listitem> <listitem> <para><link xlink:href="https://tools.ietf.org/html/rfc4511">IETF standard</link>:</para> <blockquote> <para>Clients interact with servers using a directory access protocol</para> </blockquote> </listitem> </itemizedlist> </figure> <figure xml:id="sdi_ldap_bind"> <title>LDAP Server cli bind</title> <informaltable border="1" width="100%"> <colgroup width="50%"/> <colgroup width="50%"/> <tr> <th>Command</th> <th>Result</th> </tr> <tr> <td valign="top"><screen><command xlink:href="https://linux.die.net/man/1/ldapsearch">ldapsearch</command> \ -h localhost <co linkends="sdi_ldap_bind-1.2" xml:id="sdi_ldap_bind-1.2-co"/> \ -D "cn=admin,dc=betrayer,dc=com" <co linkends="sdi_ldap_bind-2.2" xml:id="sdi_ldap_bind-2.2-co"/>\ -w password -x <co linkends="sdi_ldap_bind-3.2" xml:id="sdi_ldap_bind-3.2-co"/>\ -b "dc=betrayer,dc=com" <co linkends="sdi_ldap_bind-4.2" xml:id="sdi_ldap_bind-4.2-co"/>\ -s sub <co linkends="sdi_ldap_bind-5.2" xml:id="sdi_ldap_bind-5.2-co"/> \ -LLL <co linkends="sdi_ldap_bind-6.2" xml:id="sdi_ldap_bind-6.2-co"/></screen></td> <td valign="top"><screen>dn: dc=betrayer,dc=com <co linkends="sdi_ldap_bind-7" xml:id="sdi_ldap_bind-7-co"/> objectClass: top objectClass: dcObject objectClass: organization o: Betrayers heaven <co linkends="sdi_ldap_bind-8" xml:id="sdi_ldap_bind-8-co"/> dc: betrayer dn: cn=admin,dc=betrayer,dc=com <co linkends="sdi_ldap_bind-9" xml:id="sdi_ldap_bind-9-co"/> objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin <co linkends="sdi_ldap_bind-10" xml:id="sdi_ldap_bind-10-co"/> description: LDAP administrator userPassword:: e1NT...dE53N1E= <co linkends="sdi_ldap_bind-11" xml:id="sdi_ldap_bind-11-co"/></screen></td> </tr> </informaltable> <informaltable role="slideExclude" width="100%"> <colgroup width="50%"/> <colgroup width="50%"/> <tr> <td valign="top"><calloutlist role="slideExclude"> <callout arearefs="sdi_ldap_bind-1.2-co" xml:id="sdi_ldap_bind-1.2"> <para>An <xref linkend="glo_LDAP"/> server's <xref linkend="glo_DNS"/> name or IP address (<emphasis role="bold">h</emphasis>ost).</para> </callout> <callout arearefs="sdi_ldap_bind-2.2-co" xml:id="sdi_ldap_bind-2.2"> <para>The bind <xref linkend="glo_DN"/>. This path is being required to uniquely identify an existent user entry on the server in question. This corresponds to a login name when using <abbrev>e.g.</abbrev> web <acronym>gui</acronym> authentication.</para> </callout> <callout arearefs="sdi_ldap_bind-3.2-co" xml:id="sdi_ldap_bind-3.2"> <para>The corresponding password to the given bind <xref linkend="glo_DN"/>. The user entry must contain a corresponding userPassword hash value. The <option>-x</option> indicates using simple password based rather than <acronym xlink:href="https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer">SASL</acronym> authentication.</para> </callout> <callout arearefs="sdi_ldap_bind-4.2-co" xml:id="sdi_ldap_bind-4.2"> <para>The search will start from this uniquely defined node within the servers <xref linkend="glo_DIT"/>. In the current example we simply choose the tree's top level node.</para> </callout> <callout arearefs="sdi_ldap_bind-5.2-co" xml:id="sdi_ldap_bind-5.2"> <para>The search scope. See <link xlink:href="https://ldap.com/the-ldap-search-operation">The LDAP Search Operation</link> for details.</para> </callout> <callout arearefs="sdi_ldap_bind-6.2-co" xml:id="sdi_ldap_bind-6.2"> <para>Suppress verbose search information.</para> </callout> </calloutlist></td> <td valign="top"><calloutlist role="slideExclude"> <callout arearefs="sdi_ldap_bind-7-co" xml:id="sdi_ldap_bind-7"> <para>The <xref linkend="glo_DIT"/>'s top level node.</para> </callout> <callout arearefs="sdi_ldap_bind-8-co" xml:id="sdi_ldap_bind-8"> <para>Your organization's name</para> </callout> <callout arearefs="sdi_ldap_bind-9-co" xml:id="sdi_ldap_bind-9"> <para>The administrative user of the server. This entry will typically be created at installation time.</para> </callout> <callout arearefs="sdi_ldap_bind-10-co" xml:id="sdi_ldap_bind-10"> <para>The administrative user's <quote>common name</quote>. Note this entry corresponds to <coref linkend="sdi_ldap_bind-4.2-co"/> on the <quote>Command</quote> side of this table.</para> </callout> <callout arearefs="sdi_ldap_bind-11-co" xml:id="sdi_ldap_bind-11"> <para>The administrative user password's hash value. Note the double colon <code>::</code> indicating a base64 encoded binary value.</para> </callout> </calloutlist></td> </tr> </informaltable> </figure> <figure xml:id="sdi_ldap_Dit"> <title>Document Information Tree (<abbrev>DIT</abbrev>)</title> <mediaobject> <imageobject> <imagedata fileref="Fig/dit.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sdi_ldap_relAbsDn"> <title><productname>Relative and absolute DNs</productname></title> <mediaobject> <imageobject> <imagedata fileref="Fig/relativeDn.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sdi_ldap_userExample"> <title>User example</title> <programlisting language="none">dn: <emphasis role="red">uid=clark,ou=finance,dc=betrayer,dc=de</emphasis> <co linkends="sdi_ldap_userExample-1" xml:id="sdi_ldap_userExample-1-co"/> cn: Sandy Clark homeDirectory: /home/clark sn: Clark <emphasis role="red">uid</emphasis>: <emphasis role="red">clark</emphasis> <co linkends="sdi_ldap_userExample-2" xml:id="sdi_ldap_userExample-2-co"/> uidNumber: 21101 givenName: Sandy loginShell: /bin/bash <emphasis role="red">mail: clark@betrayer.com</emphasis> <co linkends="sdi_ldap_userExample-3" xml:id="sdi_ldap_userExample-3-co"/> <emphasis role="red">mail: finance@betrayer.com</emphasis> postOfficeBox: 10G userPassword: {SSHA}noneOfYourBusiness</programlisting> <calloutlist role="slideExclude"> <callout arearefs="sdi_ldap_userExample-1-co" xml:id="sdi_ldap_userExample-1"> <para>The entry's absolute distinguished name (<xref linkend="glo_DN"/>). This name/value list uniquely identifies an entry (an its position) within a given <xref linkend="glo_DIT"/>.</para> </callout> <callout arearefs="sdi_ldap_userExample-2-co" role="slideExclude" xml:id="sdi_ldap_userExample-2"> <para>This key/value combination is guaranteed to be unique within respect to the given parent node. It allows to identify each node with respect to its parent. So in a relational model the <quote><code>clark</code></quote> entry would become a weak entity having an identifying ownership relation to its parent organisational unit by virtue of its <code>uid</code> value.</para> <para>In other words: There is only one such entry below <emphasis role="red">ou=finance,dc=betrayer,dc=de</emphasis> having an <emphasis role="red">uid</emphasis> attribute of value <emphasis role="red">clark</emphasis>.</para> </callout> <callout arearefs="sdi_ldap_userExample-3-co" xml:id="sdi_ldap_userExample-3"> <para><xref linkend="glo_LDAP"/> allows for multi valued attributes.</para> </callout> </calloutlist> </figure> <figure xml:id="sdi_ldap_objectClasses"> <title>objectClass</title> <itemizedlist> <listitem> <para>Structuring <xref linkend="glo_LDAP"/> entry data.</para> </listitem> <listitem> <para>Categories:</para> <itemizedlist> <listitem> <para>Structural</para> </listitem> <listitem> <para>Auxiliary</para> </listitem> <listitem> <para>Abstract</para> </listitem> </itemizedlist> </listitem> </itemizedlist> </figure> <figure xml:id="sdi_ldap_objectClassesClarification"> <title>objectClass clarifications</title> <informaltable border="0"> <tr> <td valign="top"><glosslist> <glossentry> <glossterm>Abstract classes:</glossterm> <glossdef> <para>To be extended by other classes</para> </glossdef> </glossentry> <glossentry> <glossterm>Structural classes:</glossterm> <glossdef> <itemizedlist> <listitem> <para>Each entry requires exactly one.</para> </listitem> <listitem> <para>Specify the <quote>main</quote> type of object.</para> </listitem> <listitem> <para>Must not inherit from auxiliary classes.</para> </listitem> </itemizedlist> </glossdef> </glossentry> </glosslist></td> <td valign="top"><glosslist> <glossentry> <glossterm>Auxiliary classes:</glossterm> <glossdef> <itemizedlist> <listitem> <para>Provide non-conflicting supplementary information.</para> </listitem> <listitem> <para>Think of (<xref linkend="glo_Java"/>) interfaces.</para> </listitem> <listitem> <para>Must not inherit from structural classes.</para> </listitem> </itemizedlist> </glossdef> </glossentry> </glosslist></td> </tr> </informaltable> </figure> <figure xml:id="sdi_ldap_auxiliaryExample"> <title>Augmenting <classname>inetOrgPerson</classname> by <classname>posixAccount</classname></title> <programlisting language="none">Class | Instance <emphasis role="red">uid=clark,ou=finance,dc=betrayer,dc=de</emphasis> ----------------------------+--------------------------------------------------- inetOrgPerson (structural) | sn | sn: Clark cn | cn: Sandy Clark ... | <emphasis role="red">▲</emphasis> | <emphasis role="red">┃</emphasis> posixAccount (auxiliary) | <emphasis role="red">┃</emphasis> cn | <emphasis role="red">see above</emphasis> <co linkends="sdi_ldap_auxiliaryExample-1" xml:id="sdi_ldap_auxiliaryExample-1-co"/> gidNumber | gidNumber: 23113 homeDirectory | homeDirectory: /home/clark uid | uid: clark uidNumber | uidNumber: 21101 userPassword | userPassword: {SSHA}noneOfYourBusiness .....</programlisting> <calloutlist role="slideExclude"> <callout arearefs="sdi_ldap_auxiliaryExample-1-co" xml:id="sdi_ldap_auxiliaryExample-1"> <para>The <property>cn</property> attribute is being defined both in object class <classname>inetOrgPerson</classname> and <classname>posixAccount</classname>. This requires data type definitions to be compatible.</para> </callout> </calloutlist> </figure> <figure xml:id="sdi_ldap_structuralObjectClasses"> <title>Structural objectClass definitions</title> <mediaobject> <imageobject> <imagedata fileref="Fig/structuralOcInherit.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sdi_ldap_filter"> <title>Search scopes</title> <para><link xlink:href="https://tools.ietf.org/html/rfc4520">RFC 4520</link> defines <link xlink:href="https://www.iana.org/assignments/ldap-parameters/ldap-parameters.xhtml#ldap-parameters-9">three <acronym>LDAP</acronym> search scopes</link>:</para> <itemizedlist> <listitem> <para><link xlink:href="https://ldapwiki.com/wiki/BaseObject">baseObject</link> (<code>base</code>)</para> </listitem> <listitem> <para><link xlink:href="https://ldapwiki.com/wiki/SingleLevel">singleLevel</link> (<code>one</code>)</para> </listitem> <listitem> <para><link xlink:href="https://ldapwiki.com/wiki/WholeSubtree">wholeSubtree</link> (sub)</para> </listitem> </itemizedlist> </figure> <figure xml:id="sdi_ldap_filterPredicates"> <title>Predicate based queries</title> <para><link xlink:href="https://tools.ietf.org/html/rfc4520">RFC 4520</link> defines <link xlink:href="https://ldapwiki.com/wiki/LDAP%20Filter%20Choices">predicate based queries</link> using <link xlink:href="https://en.wikipedia.org/wiki/Reverse_Polish_notation">RPN</link> style:</para> <itemizedlist> <listitem> <para><code>(| (cn=k*) (uidNumber < 2000))</code></para> </listitem> </itemizedlist> </figure> <figure xml:id="sdi_ldap_bindTypes"> <title>LDAP bind types</title> <itemizedlist> <listitem> <para>Anonymous bind: No user credentials.</para> <para>Note: This typically provides limited privileges.</para> </listitem> <listitem> <para>Simple bind: User's <xref linkend="glo_DN"/> + password:</para> <programlisting language="none">DN: <emphasis role="red">uid=clark,ou=finance,dc=betrayer,dc=de</emphasis> password: <emphasis role="red">123456789</emphasis></programlisting> </listitem> </itemizedlist> </figure> <figure xml:id="sdi_ldap_ldif"> <title>LDIF exchange format</title> <itemizedlist> <listitem> <para><emphasis role="red">L</emphasis>dap <emphasis role="red">D</emphasis>ata <emphasis role="red">I</emphasis>nterchange <emphasis role="red">F</emphasis>ormat.</para> </listitem> <listitem> <para>Importing and exporting <xref linkend="glo_LDAP"/> Data.</para> </listitem> <listitem> <para>Modifying existing entries (CRUD operations).</para> </listitem> <listitem> <para>Pure <xref linkend="glo_ASCII"/>.</para> </listitem> </itemizedlist> </figure> <figure xml:id="sdi_ldap_ldifSample"> <title>LDIF sample</title> <programlisting language="none">dn: uid=clark,ou=finance,dc=betrayer,dc=de objectClass: posixAccount objectClass: inetOrgPerson cn: Sandy Clark homeDirectory: /home/clark sn: Clark uid: clark uidNumber: 21101 givenName: Sandy loginShell: /bin/bash mail: clark@betrayer.com mail: finance@betrayer.com postOfficeBox: 10G userPassword: {SSHA}noneOfYourBusiness</programlisting> </figure> <figure xml:id="sdi_ldap_ditConfigDb"> <title>OpenLdap server architecture</title> <mediaobject> <imageobject> <imagedata fileref="Fig/openldapArch.multi.svg"/> </imageobject> </mediaobject> <itemizedlist role="slideExclude"> <listitem> <para>An OpenLdap server may host multiple <xref linkend="glo_DIT"/>s each being represented by its own database backend.</para> </listitem> <listitem> <para>The server's configuration is itself being stored as a separate tree.</para> </listitem> <listitem> <para>Each tree refers to a separate database backend. Thus the above example featuring two trees is being implemented by two database instances.</para> </listitem> </itemizedlist> </figure> <section xml:id="ldapPrepare"> <title>Recommended Preparations</title> <para>The following questions might arise when starting practical work:</para> <itemizedlist> <listitem> <para>What is the <acronym>LDAP</acronym> Protocol? What is the difference between the two protocols <acronym>ldap</acronym> and <acronym>ldaps </acronym>?</para> </listitem> <listitem> <para>What does the acronym <acronym>dc</acronym> in <acronym>dc=somedomain, dc=org</acronym> stand for?</para> </listitem> <listitem> <para>What is the role of <acronym>LDAP</acronym> <property>objectclass</property> definitions? How do they relate to <acronym>LDAP</acronym> schema definitions?</para> </listitem> <listitem> <para>Describe the relationship between <acronym>LDAP</acronym> entries and <code>objectClass</code> values.</para> </listitem> <listitem> <para>Is it possible to dynamically change an entries structure?</para> </listitem> <listitem> <para>What does the term <quote>bind to an <acronym>LDAP</acronym></quote> server mean? What is an <quote>anonymous</quote> bind?</para> </listitem> <listitem> <para>Do <acronym>LDAP</acronym> servers in general support database features like transactions, ACID semantic etc.?</para> </listitem> <listitem> <para>Explain the term <quote>replication</quote> in an <acronym>LDAP</acronym> server context.</para> </listitem> <listitem> <para>Why do organizations sometimes prefer <acronym>LDAP</acronym> data repositories rather than using relational database systems?</para> </listitem> <listitem> <para>How is the <acronym>LDIF</acronym> format being organized? Explain the practical use of <acronym>LDIF</acronym> data when running a <acronym>LDAP</acronym> service.</para> </listitem> <listitem> <para><acronym>LDAP</acronym> filters</para> <itemizedlist> <listitem> <para>How do <acronym>LDAP</acronym> filters work?</para> </listitem> <listitem> <para>What is the meaning of the term <emphasis>scope</emphasis> ?</para> </listitem> <listitem> <para>How do predicate based filters connected by logical <emphasis role="bold">and/or/not</emphasis> look like?</para> </listitem> </itemizedlist> </listitem> <listitem> <para><productname>OpenLDAP</productname> server software specific questions</para> <itemizedlist> <listitem> <para>What does the term <quote>database backend</quote> refer to with respect to <productname>OpenLDAP</productname> server implementation?</para> </listitem> <listitem> <para>Why is <acronym>LDAP</acronym> replication important?</para> </listitem> <listitem> <para>How do you restrict access to <acronym>LDAP</acronym> directories?</para> </listitem> <listitem> <para>How do you speed up predicate based queries?</para> </listitem> </itemizedlist> </listitem> </itemizedlist> </section> <section xml:id="ldapExercises"> <title>Exercises</title> <section xml:id="sdiBrowseExistingLdap"> <title>Browse an existing <xref linkend="glo_LDAP"/> Server</title> <para>Reading data from an existing server requires a suitable client software. We recommend using <productname xlink:href="https://directory.apache.org/studio">Apache Directory Studio</productname>.</para> <itemizedlist> <listitem> <para>Setup Apache Directory Studio to anonymously connect to <code>ldap1.hdm-stuttgart.de</code> using <xref linkend="glo_TLS"/>. Depending on your location this may require <link xlink:href="https://wiki.mi.hdm-stuttgart.de/doku.php?id=studium:infrastruktur:vpn">VPN</link>.</para> </listitem> <listitem> <para>Browse the <xref linkend="glo_DIT"/>.</para> </listitem> <listitem> <para>Use a filter like <code>(uid=xy234)</code> to find your personal entry beneath <code>ou=userlist,dc=hdm-stuttgart,dc=de</code>. Use the corresponding <xref linkend="glo_DN"/> <abbrev>e.g.</abbrev> <code>uid=xy234, ou=userlist,dc=hdm-stuttgart,dc=de</code> to reconnect using password authentication.</para> <itemizedlist> <listitem> <para>Then browse your own entry again. Can you spot any difference? </para> </listitem> <listitem> <para>Then browse your colleague's entry. Can you spot any difference? </para> </listitem> </itemizedlist> </listitem> <listitem> <para>Repeat the previous steps by using the command line <command>ldapsearch</command> utility.</para> </listitem> </itemizedlist> </section> <section xml:id="ldapServerSetup"> <title>Set up an <productname>OpenLdap</productname> server</title> <itemizedlist> <listitem> <para><link xlink:href="https://ubuntu.com/server/docs/service-ldap">OpenLDAP Server</link> provides a good introduction how to install and configure OpenLdap.</para> </listitem> <listitem> <para><link xlink:href="http://krams915.blogspot.de/2011/01/ldap-apache-directory-studio-basic.html">http://krams915.blogspot.de/2011/01/ldap-apache-directory-studio-basic.html</link> provides some more details on populating your server with data.</para> </listitem> <listitem> <para>See <link xlink:href="http://chee-yang.blogspot.de/2012/03/ldap-introduction-to-openldap.html">http://chee-yang.blogspot.de/2012/03/ldap-introduction-to-openldap.html</link> for enabling OpenLdap server configuration by e.g. Apache Directory Studio.</para> </listitem> </itemizedlist> <tip> <orderedlist> <listitem> <para>Depending on your systems installation state you may want to add the dialog package which allows for feeding additional parameters during package installations (e.g. admin's credentials and base <xref linkend="glo_DN"/>).</para> </listitem> <listitem> <para>The <link xlink:href="https://help.ubuntu.com/lts/serverguide/openldap-server.html#openldap-server-installation">installation section</link> hints at your host system defined <xref linkend="glo_DNS"/> domain being used for deriving your server's <xref linkend="glo_DIT"/> root. You may circumvent this obstacle by calling <command>dpkg-reconfigure</command> <option>slapd</option> after installation allowing to specify additional parameters manually.</para> </listitem> <listitem> <para>In case you **ever** loose your master <code>admin</code> password see <link xlink:href="http://techiezone.rottigni.net/2011/12/change-root-dn-password-on-openldap">Change Root DN Password on OpenLDAP</link> for troubleshooting.</para> </listitem> </orderedlist> </tip> <para>You may have to install the dialog package as a prerequisite to the <productname>openldap</productname> server package:</para> <screen>aptitude install dialog aptitude install slapd</screen> <para>based on the <xref linkend="glo_DNS"/> domain <code>mi.hdm-stuttgart.de</code> the default <command>slapd</command> package installer configures a <xref linkend="glo_DIT"/> having <code>dc=mi,dc=hdm-stuttgart,dc=de</code> as root by default. Change this to <code>dc=betrayer,dc=com</code> by executing <command>dpkg-reconfigure</command> <option>slapd</option>.</para> </section> <section xml:id="ldapCompanyLdif"> <title>Populating your <xref linkend="glo_DIT"/>.</title> <para>Our aim is to populate our <acronym>LDAP</acronym> Server by the following company structure of organisational units and persons:</para> <figure xml:id="sdiLdapBetrayerComTree"> <title>An example <acronym>LDAP</acronym> Tree</title> <mediaobject> <imageobject> <imagedata fileref="Fig/ldaptree.svg"/> </imageobject> </mediaobject> </figure> <para>The <productname xlink:href="https://directory.apache.org/studio">Apache Directory Studio</productname> allows for conveniently accessing and modifying your server's <xref linkend="glo_LDAP"/> trees.</para> <tip> <para>You may want to adjust occurrences of <code>dc=betrayer;dc=com</code> by your configured <xref linkend="glo_DIT"/> root.</para> <orderedlist> <listitem> <para>You need your initial configuration <code>admin</code> password to perform a bind operation using the <code>cn=admin,dc=betrayer,dc=com</code> <xref linkend="glo_DN"/>.</para> </listitem> <listitem> <para>If you choose <quote>Use existing entry as template</quote> don't forget to purge your copy's <property>entryCsn</property> attribute belonging to your template data record being unique within your <xref linkend="glo_DIT"/>.</para> </listitem> <listitem> <para>Suitable <property>objectClass</property> and unique key attribute choices:</para> <glosslist> <glossentry> <glossterm>Organisational units <property>department</property>, <property>software</property>, <property>financial</property>, <property>devel</property>, <property>testing</property></glossterm> <glossdef> <glosslist> <glossentry> <glossterm><property>objectClass</property>:</glossterm> <glossdef> <para><property>organizationalUnit</property></para> </glossdef> </glossentry> <glossentry> <glossterm><xref linkend="glo_RDN"/> unique attribute:</glossterm> <glossdef> <para><property>ou</property></para> </glossdef> </glossentry> </glosslist> </glossdef> </glossentry> <glossentry> <glossterm>Employees Jim Smith, Audrey Bean:</glossterm> <glossdef> <glosslist> <glossentry> <glossterm><property>objectClass</property>:</glossterm> <glossdef> <para><property>inetOrgPerson</property></para> </glossdef> </glossentry> <glossentry> <glossterm><xref linkend="glo_RDN"/> unique attribute:</glossterm> <glossdef> <para><property>uid</property></para> </glossdef> </glossentry> <glossentry> <glossterm>Other attributes:</glossterm> <glossdef> <para><property>sn</property>, <property>cn</property>, <property>givenName</property>, m<property>ail</property></para> </glossdef> </glossentry> </glosslist> </glossdef> </glossentry> </glosslist> </listitem> </orderedlist> </tip> <para>When you are finished an <productname xlink:href="https://directory.apache.org/studio">Apache Directory Studio</productname> export dump of your tree might look like:</para> <programlisting language="ldif">dn: dc=betrayer,dc=com objectClass: organization objectClass: dcObject objectClass: top dc: betrayer o: betrayer.com dn: cn=admin,dc=betrayer,dc=com objectClass: organizationalRole objectClass: simpleSecurityObject cn: admin userPassword:: e1NTSEF9cEhFK0VQT0cyZ3lSeU9nanZGcXNXT2I1ekdzR2w5Q0Q= description: LDAP administrator dn: ou=departments,dc=betrayer,dc=com objectClass: top objectClass: organizationalUnit ou: departments dn: ou=software,ou=departments,dc=betrayer,dc=com objectClass: top objectClass: organizationalUnit ou: software dn: ou=financial,ou=departments,dc=betrayer,dc=com objectClass: top objectClass: organizationalUnit ou: financial dn: ou=devel,ou=software,ou=departments,dc=betrayer,dc=com objectClass: top objectClass: organizationalUnit ou: devel dn: ou=testing,ou=software,ou=departments,dc=betrayer,dc=com objectClass: top objectClass: organizationalUnit ou: testing dn: uid=bean,ou=devel,ou=software,ou=departments,dc=betrayer,dc=com objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson cn: Jim Bean sn: Bean givenName: Jim mail: bean@betrayer.com uid: bean userPassword:: e3NtZDV9YVhKL2JlVkF2TDRENk9pMFRLcDhjM3ovYTZQZzBXeHA= dn: uid=smith,ou=financial,ou=software,ou=departments,dc=betrayer,dc=com ...</programlisting> </section> <section xml:id="sdiLdapTestBind"> <title>Testing a bind operation as non - <code>admin</code> user</title> <para>Use <productname xlink:href="https://directory.apache.org/studio">Apache Directory Studio</productname> to supply a <property>userPassword</property> to e.g. <code>uid=bean,ou=devel,ou=software,ou=departments,dc=betrayer;dc=com</code> (still binding as <code>cn=admin,dc=betrayer,dc=com</code>).</para> <para>Then configure a second <productname xlink:href="https://directory.apache.org/studio">Apache Directory Studio</productname> connection profile binding as <code>uid=bean,ou=devel,ou=software,ou=departments,dc=betrayer,dc=com</code>.</para> <tip> <para>Beware: Some password hash types may not be supported. SMD5 is known to work.</para> </tip> </section> <section xml:id="ldapExtendPosixAccount"> <title>Extending an existing entry</title> <para>This exercise sheds some insight on schema support. <xref linkend="glo_LDAP"/> supports building types similar to classes in <acronym>OO</acronym> languages by means of <code>objectClass</code> definitions. On contrary these types are not static but allow for run time modification during an <xref linkend="glo_LDAP"/> object's life span.</para> <para>The entry <code>uid=bean,ou=devel,ou=software,ou=departments,dc=betrayer;dc=com</code> may be extended by the <code>objectclass</code> <code>posixAccount</code>. Construct a <acronym>LDIF</acronym> file to add the attributes <code>uidNumber</code>, <code>gidNumber</code> and <code>homeDirectory</code> by a modify/add operation.</para> </section> <section xml:id="ldapFilter"> <title>Filter based search</title> <para>Execute the following <acronym>LDAP</acronym> filter based searches:</para> <itemizedlist> <listitem> <para>All users with a <code>uid</code> attribute value starting with the letter <quote>b</quote>.</para> </listitem> <listitem> <para>All entries with either a defined <code>uid</code> attribute or a <code>ou</code> attribute starting with letter <quote>d</quote>.</para> </listitem> <listitem> <para>All users entries within the whole <xref linkend="glo_DIT"/> having a gidNumber value of 100.</para> </listitem> <listitem> <para>All user entries belonging to the billing department having a <code>uidNumber</code> value greater than 1023.</para> </listitem> <listitem> <para>All user entries within the whole <xref linkend="glo_DIT"/> having a <code>commonName</code> containing the substring <quote>ei</quote>.</para> </listitem> <listitem> <para>All user entries within the whole <xref linkend="glo_DIT"/> belonging to gidNumber == 100 or having a <code>uid</code> value starting with letter <quote>t</quote>.</para> </listitem> </itemizedlist> <tip> <para><xref linkend="glo_Soft_ApacheDirectoryStudio"/> allows both for <link xlink:href="https://nightlies.apache.org/directory/studio/2.0.0.v20210717-M17/userguide/ldap_browser/tools_filter_editor_dialog.html">filtering</link> and <link xlink:href="https://nightlies.apache.org/directory/studio/2.0.0.v20210717-M17/userguide/ldap_browser/gettingstarted_search.html">searching</link> providing nifty features like attribute name completion and syntax highlighting. You may define:</para> <itemizedlist> <listitem> <para>The <xref linkend="glo_DIT"/> entry root element (being identified by its <xref linkend="glo_DN"/>) to start your search from.</para> </listitem> <listitem> <para>The search scope being either of object, one level or subtree.</para> </listitem> <listitem> <para>Boolean expressions based on attribute values.</para> </listitem> </itemizedlist> <para><acronym linkend="glo_CLI">CLI</acronym> support is available as well <link xlink:href="http://tldp.org/HOWTO/LDAP-HOWTO/utilities.html">here</link>.</para> </tip> </section> <section xml:id="ldapTest"> <title>Accessing <xref linkend="glo_LDAP"/> data by a mail client</title> <para>The directory studio allows to reread the directory tree. As a different approach configure your local mail client (e.g. <productname>thunderbird</productname>) using your <acronym>LDAP</acronym> server for email address lookup.</para> </section> <section xml:id="sdiLdapConfig"> <title><xref linkend="glo_LDAP"/> configuration</title> <para>In contrast to many other server configurations OpenLdap supports parameter configuration within its own database backend. In other words: Some parameters are not being stored in configuration files.</para> <para>Actually OpenLdap still supports an alternate configuration file based approach which may be activated. Its use however is discouraged according to the documentation:</para> <note xlink:href="http://www.openldap.org/doc/admin24/slapdconf2.html"> <para>The older style <filename>slapd.conf</filename>(5) file is still supported, but its use is deprecated and support for it will be withdrawn in a future OpenLDAP release.</para> </note> <para>The <xref linkend="glo_DIT"/> style configuration may be altered by <xref linkend="glo_LDAP"/> clients like <command xlink:href="http://www.openldap.org/software/man.cgi?query=ldapmodify&apropos=0&sektion=0&manpath=OpenLDAP+2.4-Release&format=html">ldapmodify</command> using <filename>.ldif</filename> files. An alternate way requires altering the server's configuration <filename>/etc/ldap/slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif</filename>. We start by gathering required information. Note: The <command>ldapsearch</command> command is part of the <package>openldap-utils</package> package:</para> <screen>ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config # {0}config, config dn: olcDatabase={0}config,cn=config objectClass: olcDatabaseConfig olcDatabase: {0}config olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external ,cn=auth manage by * break <emphasis role="bold">olcRootDN: cn=admin,cn=config</emphasis> # {1}mdb, config dn: olcDatabase={1}mdb,cn=config ... <emphasis role="bold">olcRootDN: cn=admin,dc=hdm-stuttgart,dc=de olcRootPW: {SSHA}7M0gUyHOH7cfK1z9amqgK0uQcn84AuYw</emphasis> ...</screen> <para>The above lines appear near in the tail section. We see two databases <code>{0}</code> and <code>{1}</code> representing two different <xref linkend="glo_DIT"/>s namely <code>cn=config</code> (the configuration database) and <code>dc=hdm-stuttgart,dc=de</code> (containing our <quote>actual</quote> directory data).</para> <para>The configuration database does have a <code>olcRootDN: cn=admin,cn=config</code> entry but a corresponding <parameter>olcRootPW</parameter> attribute is yet missing. This limits configuration access to <code>localhost</code>.</para> <para>External access e.g. by <productname xlink:href="https://directory.apache.org/studio">Apache Directory Studio</productname> requires adding this credential attribute. This first-time (bootstrapping) configuration must be done locally by means of an <xref linkend="glo_LDIF"/> file adding a (possibly different) hashed password:</para> <screen>root@sdi8a:~# cat ~/add_olcRootPW.ldif dn: olcDatabase={0}config,cn=config add: olcRootPW olcRootPW: {ssha}pHE+EPOG2gyRyOgjvFqsWOb5zGsGl9CD</screen> <para>Activating this configuration my be effected by using <command xlink:href="http://www.openldap.org/software/man.cgi?query=ldapmodify&apropos=0&sektion=0&manpath=OpenLDAP+2.4-Release&format=html">ldapmodify</command>:</para> <screen>root@sdi8a:~# ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ~/add_olcRootPW.ldif modifying entry "olcDatabase={0}config,cn=config"</screen> <para>This activation in turn enables a new account:</para> <glosslist> <glossentry> <glossterm>Bind DN:</glossterm> <glossdef> <para><option>cn=admin,cn=config</option></para> </glossdef> </glossentry> <glossentry> <glossterm>Bind password</glossterm> <glossdef> <para><option>*****</option></para> </glossdef> </glossentry> <glossentry> <glossterm>Base DN</glossterm> <glossdef> <para><option>cn=config</option></para> </glossdef> </glossentry> </glosslist> <para>When configuring a connection to access this configuration database you may have to untick Apache Directory Studio's <quote>Get base DNs from Root DSE</quote> box in the <quote>Browser Options</quote> tab. Then configure "cn=config" in the <quote>Base DN:</quote> manually.</para> <para>We may now dynamically alter ourserver configuration parameters remotely using e.g. <link xlink:href="https://directory.apache.org/studio">Apache directory studio</link>:</para> <mediaobject> <imageobject> <imagedata fileref="Fig/ldapConfig.png"/> </imageobject> </mediaobject> <para>A prominent configuration change candidate is our server's log level: Depending on your success during subsequent exercises you may want to adjust <parameter xlink:href="http://www.zytrax.com/books/ldap/ch6/#loglevel">olcLogLevel</parameter> in <code>cn=config</code> appropriately.</para> <caution> <para>Using <link xlink:href="https://serverfault.com/questions/324608/how-do-i-get-openldap-on-centos-6-to-write-anything-to-its-log-files#answer-499902">using olcLogFile</link> will not override OpenLdap using your host's syslog facility: The file will be created (provided write permission is being granted) but log messages will still be written to <filename>/var/log/syslog</filename>.</para> <para>Thus creating a separate <filename>ldap.log</filename> file requires <link xlink:href="http://www.tldp.org/HOWTO/LDAP-HOWTO/logs.html">configuring your system's syslog daemon appropriately</link>. Current systems allow for creating a file i.e. <filename>/etc/rsyslog.d/slapd.conf</filename> containing the desired log data redirection. Do not forget to restart your service.</para> </caution> </section> <section xml:id="sdiSectLdapOsSupport"> <title><xref linkend="glo_LDAP"/> based user login</title> <caution xml:id="sdiSectLdapOsSupportPamCaution"> <para>In this exercise you'll modify your system's <quote xlink:href="https://www.redhat.com/sysadmin/pluggable-authentication-modules-pam">Pluggable Authentication Modules (PAM)</quote>. You may <emphasis>easily</emphasis> get locked out due to an unintended misconfiguration. Stick to the following procedures avoiding this type of mishap:</para> <orderedlist> <listitem> <para>Create a backup <filename>/root/pam.tgz</filename> of your working <acronym>PAM</acronym> configuration being represented by <filename>/etc/pam.conf</filename> and files below <filename>/etc/pam.d</filename> beforehand:</para> <screen>cd /etc tar zcf /root/pam.tgz pam.conf pam.d</screen> <para>Check the resulting archive to contain something like:</para> <screen language="bash">root@sdi12b:~# tar ztf /root/pam.tgz pam.conf pam.d/ pam.d/newusers pam.d/sshd ... pam.d/chfn pam.d/chsh</screen> </listitem> <listitem> <para>Always keep an independent (emergency) shell open when tinkering with <acronym>PAM</acronym>. In case you are no longer able to log in <abbrev>i.e.</abbrev> using <xref linkend="glo_ssh"/> this one allows for restoring your working configuration:</para> <screen language="bash">cd /etc mv pam.d pam.d.orig # Save your current (not working) PAM mv pam.conf pam.conf.orig # configuration for later inspection. tar zxf /root/pam.tgz # Restore your working PAM configuration</screen> <para>After this try to log in again.</para> </listitem> <listitem> <para>Prior to rebooting (and thus loosing your emergency login shell) always try logging in thereby testing your system's accessibility.</para> </listitem> </orderedlist> </caution> <para>Configure your second VM (the one without <xref linkend="glo_LDAP"/> Server) to allow for user login purely based on <xref linkend="glo_LDAP"/>.</para> <itemizedlist> <listitem> <para>Activation of OS level <xref linkend="glo_LDAP"/> user, group and password support is being outlined in <link xlink:href="https://computingforgeeks.com/how-to-configure-ubuntu-as-ldap-client">Configure LDAP Client on Ubuntu</link>.</para> </listitem> <listitem> <para><xref linkend="glo_LDAP"/> user entry DN's must be addressed by uid e.g. <code>uid=ldaptest,ou=people,...</code> . On successful configuration you should see:</para> <screen>$ id ldaptest uid=1001(ldaptest) gid=1001(ldaptest) groups=1001(ldaptest)</screen> <para>A <quote>id: ‘<code>ldaptest</code>’: no such user</quote> message indicates your <xref linkend="glo_LDAP"/> setup does not (yet) work.</para> <tip> <itemizedlist> <listitem> <para><filename>/etc/nsswitch.conf</filename> should contain:</para> <programlisting language="none">passwd: files ldap group: files ldap shadow: files ldap</programlisting> <para>What does this mean?</para> </listitem> <listitem> <para>Shut down you <command xlink:href="https://linux.die.net/man/8/nscd">nscd</command> daemon. Why?</para> </listitem> <listitem> <para>Your Secure Shell Daemon configuration /etc/ssh/sshd_config should contain:<programlisting language="bourne">PasswordAuthentication yes</programlisting></para> </listitem> <listitem> <para>After changing your configuration a reboot might be required.</para> </listitem> <listitem> <para>For debugging login attempts you may want setting your <xref linkend="glo_LDAP"/> server's <link xlink:href="http://www.zytrax.com/books/ldap/ch6/#loglevel">logging level</link> to at least including <option>conns</option>, <option>config</option> and <option>stats</option>.</para> </listitem> </itemizedlist> </tip> </listitem> <listitem> <para>Create the required user home directory manually beforehand setting owner and group accordingly.</para> </listitem> </itemizedlist> <tip> <para><xref linkend="glo_LDAP"/> user information (<property>uid</property>, common name, numerical id, group information ...) will reside on your <xref linkend="glo_LDAP"/> Server rather than locally in <filename>/etc/passwd</filename>, <filename>/etc/group</filename> and <filename>/etc/shadow</filename>.</para> </tip> </section> <section xml:id="diSectLdapBackupRestore"> <title>Backup and recovery / restore</title> <para>Take the hard way to test backup and restore:</para> <orderedlist> <listitem> <para>Set up a <quote>replica</quote> <xref linkend="glo_LDAP"/> Server on your second host system.</para> </listitem> <listitem> <para>Export both databases (configuration and <quote>real</quote> data) from your production server using <command xlink:href="http://linux.die.net/man/8/slapcat">slapcat</command>.</para> </listitem> <listitem> <para>Restore the exported data on your replica using <command xlink:href="http://linux.die.net/man/8/slapadd">slapadd</command>.</para> </listitem> </orderedlist> </section> <section xml:id="sdiSectLdapByJava"> <title>Accessing <xref linkend="glo_LDAP"/> by a <xref linkend="glo_Java"/> application.</title> <para>Accessing <xref linkend="glo_LDAP"/> requires a suitable client component. A standard <xref linkend="glo_JDK"/> or <xref linkend="glo_JRE"/> ships with a <acronym xlink:href="https://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-ldap.html">JNDI</acronym> provider. The <xref linkend="glo_API"/> however requires a lot of boilerplate code.</para> <para><orgname xlink:href="http://www.ldaptive.org">Ldaptive</orgname> offers a promising client provider <xref linkend="glo_API"/>. Start a <xref linkend="glo_Maven"/> based <xref linkend="glo_Soft_Eclipse"/> project which reads your own HdM <xref linkend="glo_LDAP"/> data being provided by the MI replica server <code>ldap1.mi.hdm-stuttgart.de</code>.</para> <para>This server allows for retrieving all attributes belonging to your personal records. Thus an authenticated bind using your HdM credentials is mandatory. Use <xref linkend="glo_TLS"/> to prevent password sniffing!</para> <tip> <itemizedlist> <listitem> <para>Read the <link xlink:href="http://www.ldaptive.org/#quick-start-guide">quick start guide</link> and consult the <link xlink:href="http://www.ldaptive.org/javadocs">Ldaptive API</link>.</para> </listitem> <listitem> <para>Using <orgname xlink:href="http://www.ldaptive.org">Ldaptive</orgname> may be accomplished by adding the following <xref linkend="glo_Maven"/> dependencies to your project's <filename>pom.xml</filename> file:</para> <programlisting language="none"><project xmlns="http://maven.apache.org/POM/4.0.0" ... > <properties> <slf4j.version><emphasis role="red">find my current version on Maven central</emphasis></slf4j.version> ... </properties> <dependencies> <dependency> <groupId>org.ldaptive</groupId> <artifactId>ldaptive</artifactId> <version><emphasis role="red">find my current version on Maven central</emphasis></version> </dependency> <dependency> <!-- required for ldaptive's internal logging --> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>${slf4j.version}</version> </dependency> ...</programlisting> <tip> <para>Follow <link xlink:href="https://www.swtestacademy.com/how-to-configure-simple-logger-slf4j-log-levels">How To Configure Simple Logger slf4j Log Levels</link> avoiding unrelated <productname>Ldaptive</productname> logging info.</para> </tip> </listitem> </itemizedlist> </tip> <para>The expected output with respect to the given initial data should resemble:</para> <screen>ou=departments,dc=betrayer,dc=com ou: {departments} objectClass: {top, organizationalUnit} ------------------------------------------------------- ou=software,ou=departments,dc=betrayer,dc=com ou: {software} objectClass: {top, organizationalUnit} ------------------------------------------------------- ou=devel,ou=software,ou=departments,dc=betrayer,dc=com ou: {devel} objectClass: {top, organizationalUnit} ------------------------------------------------------- uid=bean,ou=devel,ou=software,ou=departments,dc=betrayer,dc=com uid: {bean} mail: {bean@betrayer.com} givenName: {Jim} cn: {Jim Bean} sn: {Bean} objectClass: {top, person, organizationalPerson, inetOrgPerson, posixAccount} userPassword: {{smd5}aXJ/beVAvL4D6Oi0TKp8c3z/a6Pg0Wxp} gidNumber: 1000 homeDirectory: /home/bean uidNumber: 1000 ------------------------------------------------------- ou=testing,ou=software,ou=departments,dc=betrayer,dc=com ou: {testing} objectClass: {top, organizationalUnit} ------------------------------------------------------- ou=financial,ou=departments,dc=betrayer,dc=com ou: {financial} objectClass: {top, organizationalUnit} ...</screen> <para>Remarks:</para> <itemizedlist> <listitem> <para>Descend a given arbitrary LDAP tree recursively.</para> </listitem> <listitem> <para>Indent according to each entries hierarchy level. In the above example <code>ou=software,ou=departments,dc=betrayer,dc=com</code> being a child of <code>ou=departments,dc=betrayer,dc=com</code> receives an extra indent.</para> </listitem> <listitem> <para>Mind single and multi valuedness of attributes: In the above example <code>mail: {bean@betrayer.com}</code> is multivalued in contrast to <code>homeDirectory: /home/bean</code>. The brace pairs {...} denote attribute sets. The server's schema information is your friend. Consider the following hints:</para> <programlisting language="java">ConnectionFactory factory = DefaultConnectionFactory ... ; Schema schema = SchemaFactory.createSchema(factory); ... schema.getAttributeType(...).isSingleValued() ...</programlisting> </listitem> </itemizedlist> </section> </section> </chapter>