<chapter id="ldap-integration">
<title>LDAP Integration</title>
<para>
OTRS kann an mehreren Stellen ein LDAP Verzeichnis als Quelle nutzen. Die folgende Anleitung beschreibt, wie ein Active Directory Server mit OTRS genutzt wird. Das Beispiel dient auch dem grunds&auml;tzlichen Verst&auml;ndnis, wie gegen einen LDAP-Server gebunden wird.
</para>

<section id="ldap-integration-ad">
<title>Active Directory</title>
<para>
Diese Anleitung beschreibt, wie OTRS mit Microsoft's Active Directory (im folgenden AD genannt) integriert wird. Via LDAP werden sowohl Agenten wie auch Kunden authentifiziert, und die Kunden-informationen beschafft werden.
</para> 
<para> 
Wir nehmen an, dass OTRS auf einem Linux Server l&auml;uft und dass Sie wissen, wie mit dem AD und dessen administrativen Werkzeugen umzugehen ist.
</para>
<para> 
Die Nennung spezifischer Produkte und Marken erfolgt ohne weitergehende Absicht.
</para>
<para> 
F&uuml;hlen Sie sich aufgerufen, vor &Auml;nderungen am System ein desselben Backup vorzunehmen, und dies auch regelm&auml;&szlig;ig zu tun.
</para> 

<section id="ldap-integration-ad-preparations">
<title>Vorbereitungen</title>

<para> 
Als einzige Voraussetzung f&uuml;r den OTRS Server ergibt sich ein instal.liertes Net::LDAP. Das Modul kann von http://ldap.perl.org/ heruntergeladen werden.
</para> 
<para> 
Zudem ist es eine gute Idee, zun&auml;chst einen OTRS-Adminzugange in der Datenbank anzulegen, oder Sie werden sich nicht einloggen k&ouml;nnen. Erstellen Sie einen Admin, dessen Name dem im AD entspricht.
</para> 
<para> 
Um die LDAP-F&auml;higkeiten des OTRS mit einem AD nutzen zu k&ouml;nnen, ben&ouml;tigen Sie mindestens einen AD-Controller. Dieser muss als sog. Global Catalog Server (GCS) fungieren, um Authentifizierungen gegen das AD zu erlauben.
</para> 
<para> 
Sie k&ouml;nnen das AD sowohl von Windows 2000 als auch von Windows 2003 aus nutzen.
</para> 
<para> 
Details, die w&auml;hrend der Konfiguration von OTRS und LDAP ben&ouml;tigt werden.
<itemizedlist>
<listitem>Hostname des AD Servers</listitem>
<listitem>Basis-DN Ihres AD-Baumes</listitem>
<listitem>Username und Passwort, mit denen die LDAP-Abfragen durchgef&uuml;hrt werden (AD erlaubt keine anonymen Abfragen!)</listitem>
</itemizedlist>
</para> 

</section>

<section id="ldap-integration-ad-config">
<title>Konfiguration</title>

<section id="ldap-integration-ad-config-windows">
<title>Konfiguration des Active Directory</title>
<para>
Erstellen Sie im AD einen neuen Benutzer mit dem werkzeug "AD Benutzer und Computer". Der Benutzer muss lediglich die Rechte eines regul&auml;ren Dom&auml;nen-Benutzers besitzen.
Existiert eine Richtlinie, die nach einer gewissen Zeit zum Wechsel des Passwortes auffordern wird, konfigurieren Sie den Zugang so, dass das Password nie abl&auml;uft.
</para>
</section>

<section id="ldap-integration-ad-config-otrs">
<title>OTRS LDAP Optionen</title>

<para>
OTRS kann LDAP an drei Stellen nutzen.
<itemizedlist>
<listitem>Authentifizierung der Agenten</listitem>
<listitem>Authentifizierung der Kundenbenutzer</listitem>
<listitem>Daten der Kundenbenutzer</listitem>
</itemizedlist>
</para>
<para>
Die beiden Module betreffend Kundenbenutzer werden am besten zusammen verwendet, oder es ist viel Handarbeit notwendig. Diese Anleitung bezieht sich nicht auf die wechselseitige Nutzung der beiden Optionen.
</para>

</section>

</section>

<section id="ldap-integration-ad-agent-auth">
<title>Authentifizierung der Agenten</title>
<para>
Bearbeiten Sie die Konfigurationsdatei von OTRS, &uuml;blicherweise zu finden in &lt;OTRS_HOME&gt;/Kernel/Config.pm.
</para>
<para>
F&uuml;gen Sie folgendes hinzu:
</para>
<example>
<title>Kernel/Config.pm - AuthModule</title>
<programlisting>
   $Self->{'AuthModule'} = 'Kernel::System::Auth::LDAP';
</programlisting>
</example>
<para>
Hiermit wird der Modus zur Authentifizierung auf LDAP umgeschaltet.
</para>
<para>
Nun f&uuml;gen Sie die folgenden drei Zeilen hinzu:
</para>
<example>
<title>Kernel/Config.pm - AuthModule::LDAP Einstellungen</title>
<programlisting>
   $Self->{'AuthModule::LDAP::Host'} = '[AD_server]'; 
   $Self->{'AuthModule::LDAP::BaseDN'} = '[base_dn]';
   $Self->{'AuthModule::LDAP::UID'} = 'sAMAccountName';
</programlisting>
</example>
<para>
Ersetzen Sie [AD_server] mit dem Hostnamen (w2kad.example.com) oder der IP Adresse Ihres AD Servers (192.168.1.23).
</para>
<para>
Ersetzen Sie [base_dn] mit der Basis-DN Ihres AD-Baumes. Sie folgt dieser Syntax "dc=example, dc=com".
</para>
<para>
Ein einfacher Weg, an die Basis-DN zu gelangen, bietet das Werkzeug "AD Benutzer und Computer". Der Name des AD-Baumes zeigt den Dom&auml;nennamen als &quote;domain.tld&quote; oder &quote;subdomain.domain.tld&quote;, je nachdem, wie Ihr AD aufgesetzt wurde. Bei der Konversion in eine DN werden obige Beispiele dann zu &quote;dc=domain, dc=tld"&quote; und &quote;dc=subdomain, dc=domain, dc=com&quote;.
</para>
<para>
Finden Sie die Basis-DN Ihres ADs immer noch nciht, k&ouml;nnen Sie weitere Tools nutzen, wie etwa LDIFDE (finden Sie auf dem AD Server) oder ADSI Edit (von der W2K Support Kit CD/Resource Kit CD).
</para>
<para>
Da das AD ein spezielles und von einem reinen inetOrg abweichendes Schema nutzt, m&uuml;ssen wir "sAMAccountName" f&uuml;r die UID des Zugangs benutzen. Dieses Merkmal ist bestimmend im AD.
</para>
<para>
Sie m&uuml;ssen den Zugang angeben, &uuml;ber den OTRS mit dem AD kommuniziert. Dies geschieht mit den folgenden Einstellungen:</para>
<example>
<title>Kernel/Config.pm - AuthModule::LDAP Einstellungen zum SearchUser</title>
<programlisting>
  $Self->{'AuthModule::LDAP::SearchUserDN'} = '[user_dn]';
  $Self->{'AuthModule::LDAP::SearchUserPw'} = '[passwort]';
</programlisting>
</example>
<para>
Ersetzen Sie [user_dn] mit der vollst&auml;ndigen DN des gew&uuml;nschten AD/OTRS Benutzers. Folgen Sie der Standard-LDAP-Syntax. Die vollst&auml;ndige DN richtet sich nach dem Kontainer, in dem Sie den Benutzerzugang mit "AD Benutzer und Gruppen" erstellt haben. Haben Sie den Benutzer im Standard-Kontainer "Benutzer" erstellt, lautet die Syntax "cn=Vorname Nachname, cn=Benutzer, [base_dn]". Wenn Sie unsicher sind, welches die korrekte DN ist, f&uuml;hren Sie LDIFDE.EXE auf Ihrem AD controller aus und durchsuchen sie dessen Ausgabe.
</para>
<para>
Ersetzen Sie [passwort] mit dem Password dieses Zugangs.
</para>

</section>

<section id="ldap-integration-ad-customer-auth">
<title>Authentifizierung der Kundenbenutzer</title>
<para>
Die Konfiguration der Authentifizierung der Kundenbenutzer wird durch folgende Parameter bestimmt:
</para>
<example>
<title>Kernel/Config.pm - Customer::AuthModule LDAP Einstellungen</title>
<programlisting>
  $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::LDAP';
  $Self->{'Customer::AuthModule::LDAP::Host'} = '[AD_server]';
  $Self->{'Customer::AuthModule::LDAP::BaseDN'} = '[base_dn]';
  $Self->{'Customer::AuthModule::LDAP::UID'} = 'sAMAccountName';
  $Self->{'Customer::AuthModule::LDAP::SearchUserDN'} = '[user_dn]';
  $Self->{'Customer::AuthModule::LDAP::SearchUserPw'} = '[passwort]';
</programlisting>
</example>
<para>
Ersetzen Sie [AD_server] mit dem Hostnamen Ihres AD Servers, z.B.: w2kad.example.com.
</para>
<para>
Ersetzen Sie [base_dn] mit der DN des Astes, in dem Ihre Kundenbenutzer untergebracht sind. Befinden Sich alle Kundenbenutzer in einem "People" Kontainer, spezifizieren Sie diesen als Basis-DN f&uuml;r CustomerAuth: "ou=People, dc=example, dc=com". Haben Sie Kundenbenutzerdaten in mehreren Kontainern, richten Sie mehrere LDAP-Quellen ein. Sie k&ouml;nnen $Self->{CustomerUser1} bis $Self->{CustomerUser10} zus&auml;tzlich erstellen.
</para>
<para>
Ersetzen Sie [user_dn] wie oben mit dem OTRS/AD Benutzer und [passwort] mit dessen Passwort.
</para>
</section>

<section id="ldap-integration-ad-customer-data">
<title>Daten der Kundenbenutzer</title>
<para>
Dies sind die notwendigen Einstellungen, um die Daten der Kundenbenutzer aus dem LDAP/AD zu lesen:
</para>
<example>
<title>Kernel/Config.pm - CustomerUser::LDAP Einstellungen</title>
<programlisting>
  $Self->{CustomerUser} = {
    Module => 'Kernel::System::CustomerUser::LDAP',
    Params => {
      Host => '[AD_server]',
      BaseDN => '[base_dn]',
      SSCOPE => 'sub',
      UserDN => '[user_dn]',
      UserPw => '[password]',
    },
    CustomerKey => 'sAMAccountName',
    CustomerID => '[customer_id]',
    CustomerUserListFields => ['sAMAccountName', 'cn', 'mail'],
    CustomerUserSearchFields => ['sAMAccountName', 'cn', 'mail'],
    CustomerUserPostMasterSearchFields => ['mail'],
    CustomerUserNameFields => ['givenname', 'sn'],
    Map => [
      # note: Login, Email and CustomerID needed!
      # var, frontend, storage, shown, required, storage-type
#       [ 'UserSalutation', 'Title', 'title', 1, 0, 'var' ],
      [ 'UserFirstname', 'Firstname', 'givenname', 1, 1, 'var' ],
      [ 'UserLastname', 'Lastname', 'sn', 1, 1, 'var' ],
      [ 'UserLogin', 'Login', 'sAMAccountName', 1, 1, 'var' ],
      [ 'UserEmail', 'Email', 'mail', 1, 1, 'var' ],
      [ 'UserCustomerID', 'CustomerID', 'mail', 0, 1, 'var' ],
#       [ 'UserPhone', 'Phone', 'telephonenumber', 1, 0, 'var' ],
#       [ 'UserAddress', 'Address', 'postaladdress', 1, 0, 'var' ],
#       [ 'UserComment', 'Comment', 'description', 1, 0, 'var' ],
    ],
  };
</programlisting>
</example>
<para>
Ersetzen Sie [AD_server] mit dem Namen oder der IP Adresse Ihres AD servers.
</para>
<para>
Ersetzen Sie [base_dn] mit der DN des Astes Ihrer Kundenbenutzer, z.B.: "ou=People, dc=example, dc=com".
</para>
<para>
Ersetzen Sie [user_dn] und [password] wie gehabt.
</para>
<para>
Ersetzen Sie [customer_id] mit einem geeigneten Attribut. &Uuml;blich ist hier das Attribut 'mail' oder 'o'.
</para>
<para>
Mit CustomerUserListFields bestimmen Sie, wie Kundenbenutzer angezeigt w&auml;hrend der Arbeit werden. Mit den obigen Standardeinstellungen wird der Kundenbenutzer angeziegt als: "Username Nachhname email@addresse"
</para>
<para>
M&ouml;chten Sie lediglich die eMail Adressen anzeigen, &auml;ndern Sie den Eintrag so ab, dass er nur noch 'mail' enth&auml;lt. Sie k&ouml;nnen hier auch weitere LDAP/AD Attribute hinzuf&uuml;gen.
</para>
<para>
CustomerUserSearchFields hat dieselben Optionen wie CustomerUserListFields. Hiermit bestimmen Sie, &uuml;ber welche Attribute Kundenbesucher gesucht werden. F&uuml;gen Sie bspw. das Attribut 'o' hinzu, gen&uuml;gt die Angabe des Firmennamens, um alle Kundenbenutzer einer Firma aufzulisten, sofern dieser Wert im AD vorhanden ist.
</para>

</section>

<section id="ldap-integration-ad-tnt">
<title>Tipps &amp; Tricks</title>

<section id="ldap-integration-ad-tnt-groupdn">
<title>Control who's let in</title>
<para>
Verhindern Sie, dass Kundenbernutzer und Agenten sich im OTRS einloggen k&ouml;nnen. Dies wird umso wichtiger, je gr&ouml;&szlig;er und un&uuml;bersichtlicher Ihre AD-Strukur ist/wird. Legen Sie eine Gruppe der Objectklasse posixGroup an und f&uuml;llen Sie sie mit entweder der UID oder der DN der gew&uuml;nschten Mitglieder.
</para>
<example>
<title>Kernel/Config.pm - GroupDN f&uuml;r Agenten</title>
<programlisting>
  $Self->{'AuthModule::LDAP::GroupDN'} = 'cn=otrsallow_A, ou=posixGroups, dc=example, dc=com';
  $Self->{'AuthModule::LDAP::AccessAttr'} = 'memberUid';
 #$Self->{'AuthModule::LDAP::UserAttr'} = 'UID';
  $Self->{'AuthModule::LDAP::UserAttr'} = 'DN';
</programlisting>
</example>
<example>
<title>Kernel/Config.pm - GroupDN for Customers</title>
<programlisting>
  $Self->{'Customer::AuthModule::LDAP::GroupDN'} = 'cn=otrsallow_C, ou=posixGroups, dc=example, dc=com';
  $Self->{'Customer::AuthModule::LDAP::AccessAttr'} = 'memberUid';
 #$Self->{'Customer::AuthModule::LDAP::UserAttr'} = 'UID';
  $Self->{'Customer::AuthModule::LDAP::UserAttr'} = 'DN';
</programlisting>
</example>
</section>

<section id="ldap-integration-ad-tnt-example">
<title>Konfigurationsbeispiel</title>
<para>
Dies ist ein komplettes Beispiel, wie OTRS f&uuml;r die Authentifizierung von Kundenbenutzern und Agenten gegen ein AD konfiguriert werden kann. Auch die Kundenbenutzerdaten werden aus dem AD gelesen, die Datenbankeinstellungen wurden hier ebenfalls beibehalten.
</para>
<para>
Die benutzten Einstel,lungen:
<itemizedlist>
<listitem>
Windows AD Server: w2kad.example.com
</listitem>
<listitem>
Windows OTRS/AD Benutzer: otrs (Vollst&auml;ndiger Name: OTRS Service)
</listitem>
<listitem>
Windows OTRS/AD Benutzer Passwort: secret
</listitem>
<listitem>
Windows OTRS/AD Benutzer DN: cn=OTRS Service, ou=People, dc=example, dc=com
</listitem>
<listitem>
Windows Dom&auml;ne: example.com
</listitem>
<listitem>
Windows LDAP Basis-DN: dc=example, dc=com
</listitem>
<listitem>
Windows Benutzer Container: People
</listitem>
<listitem>
Windows Benutzer LDAP DN: ou=People, dc=example, dc=com
</listitem>
<listitem>
Windows Agenten LDAP DN: ou=People, dc=example, dc=com
</listitem>

</itemizedlist>
</para>
<example>
<title>Kernel/Config.pm - AuthModule LDAP settings</title>
<programlisting>
  #------------------------------------------------------------------------
  # Start of Example Config
  $Self->{'AuthModule'} = 'Kernel::System::Auth::LDAP';
  $Self->{'AuthModule::LDAP::Host'} = 'w2kad.example.com';
  $Self->{'AuthModule::LDAP::BaseDN'} = 'dc=example, dc=com';
  $Self->{'AuthModule::LDAP::UID'} = 'sAMAccountName';

  $Self->{'AuthModule::LDAP::SearchUserDN'} = 'cn=OTRS Service, ou=People, dc=example, dc=com';
  $Self->{'AuthModule::LDAP::SearchUserPw'} = 'secret';


  # This is an example configuration for an LDAP auth. backend.
  # (take care that Net::LDAP is installed!)
  $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::LDAP';
  $Self->{'Customer::AuthModule::LDAP::Host'} = 'w2kad.example.com';
  $Self->{'Customer::AuthModule::LDAP::BaseDN'} = 'ou=People, dc=example, dc=com';
  $Self->{'Customer::AuthModule::LDAP::UID'} = 'sAMAccountName';

  # The following is valid but would only be necessary if the
  # anonymous user do NOT have permission to read from the LDAP tree
  $Self->{'Customer::AuthModule::LDAP::SearchUserDN'} = 'cn=OTRS Service, ou=People, dc=example, dc=com';
  $Self->{'Customer::AuthModule::LDAP::SearchUserPw'} = 'secret';

  # CustomerUser
  # (customer user database backend and settings)
    $Self->{CustomerUser} = {
        Name => 'Datenbank',
        Module => 'Kernel::System::CustomerUser::DB',
        Params => { Table => 'customer_user',
            # to use an external database
#           DSN => 'DBI:odbc:yourdsn',
#           DSN => 'DBI:mysql:database=customerdb;host=customerdbhost',
#           User => '', Password => '',
        },
        # customer uniq id
        CustomerKey => 'login',
        CustomerID => 'customer_id',
        CustomerValid => 'valid_id',
        CustomerUserListFields => ['first_name', 'last_name', 'email'],
#       CustomerUserListFields => ['login', 'first_name', 'last_name', 'customer_id', 'email'],
        CustomerUserSearchFields => ['login', 'last_name', 'customer_id'],
        CustomerUserSearchPrefix => '',
        CustomerUserSearchSuffix => '*',
        CustomerUserSearchListLimit => 250,
        CustomerUserPostMasterSearchFields => ['email'],
        CustomerUserNameFields => ['salutation', 'first_name', 'last_name'],
#       ReadOnly => 1,
        Map => [
            # note: Login, Email and CustomerID needed!
            # var, frontend, storage, shown, required, storage-type, http-link
            [ 'UserSalutation', 'Salutation', 'salutation', 1, 0, 'var' ],
            [ 'UserFirstname', 'Firstname', 'first_name', 1, 1, 'var' ],
            [ 'UserLastname', 'Lastname', 'last_name', 1, 1, 'var' ],
            [ 'UserLogin', 'Login', 'login', 1, 1, 'var' ],
            [ 'UserPassword', 'Password', 'pw', 0, 1, 'var' ],
            [ 'UserEmail', 'Email', 'email', 0, 1, 'var' ],
            [ 'UserCustomerID', 'CustomerID', 'customer_id', 0, 1, 'var' ],
            [ 'UserComment', 'Comment', 'comments', 1, 0, 'var' ],
            [ 'ValidID', 'Valid', 'valid_id', 0, 1, 'int' ],
        ],
    };

  # CustomerUser1
  # (customer user ldap backend and settings)
  $Self->{CustomerUser1} = {
    Module => 'Kernel::System::CustomerUser::LDAP',
    Params => {
      # ldap host
      Host => 'w2kad.example.com',
      # ldap base dn
      BaseDN => 'ou=People, dc=example, dc=com',
      # search scope (one|sub)
      SSCOPE => 'sub',
      # The following is valid but would only be necessary if the
      # anonymous user does NOT have permission to read from the LDAP tree
      UserDN => 'cn=OTRS Service, ou=People, dc=example, dc=com',
      UserPw => 'secret',
      AlwaysFilter => '',
      SourceCharset => 'utf-8',
      DestCharset => 'iso-8859-1',
    },
    # customer uniq id
    CustomerKey => 'sAMAccountName',
    # customer #
    CustomerID => 'mail',
    CustomerUserListFields => ['sAMAccountName', 'cn', 'mail'],
    CustomerUserSearchFields => ['sAMAccountName', 'cn', 'mail'],
    CustomerUserSearchPrefix => '',
    CustomerUserSearchSuffix => '*',
    CustomerUserSearchListLimit => 250,
    CustomerUserPostMasterSearchFields => ['mail'],
    CustomerUserNameFields => ['givenname', 'sn'],
    Map => [
      # note: Login, Email and CustomerID needed!
      # var, frontend, storage, shown, required, storage-type
      #[ 'UserSalutation', 'Title', 'title', 1, 0, 'var' ],
      [ 'UserFirstname', 'Firstname', 'givenname', 1, 1, 'var' ],
      [ 'UserLastname', 'Lastname', 'sn', 1, 1, 'var' ],
      [ 'UserLogin', 'Login', 'sAMAccountName', 1, 1, 'var' ],
      [ 'UserEmail', 'Email', 'mail', 1, 1, 'var' ],
      [ 'UserCustomerID', 'CustomerID', 'mail', 0, 1, 'var' ],
      [ 'UserPhone', 'Phone', 'telephonenumber', 1, 0, 'var' ],
      #[ 'UserAddress', 'Address', 'postaladdress', 1, 0, 'var' ],
      #[ 'UserComment', 'Comment', 'description', 1, 0, 'var' ],
    ],
  };
  # End example config
  #------------------------------------------------------------------------
</programlisting>
</example>
</section>

</section>

</section>

</chapter>
