Blog

Kundenbackend mit LDAP

07.07.2017 // Renée Bäcker

OTRS ist an vielen Stellen einfach durch Konfiguration an die eigenen Bedürfnisse anpassbar. So auch beim Einbinden unterschiedlichster Quellen für Kundendaten. Egal ob man LDAP oder eine relationale Datenbank wie MySQL, PostgreSQL nutzt - eine Änderung in der Konfiguration reicht, um eine oder mehrere dieser Quellen einzubinden.

Man sollte nur auf eines achten: Die Kernel/Config/Defaults.pm sollte nie geändert werden. Das macht ein OTRS-Upgrade nur unnötig umständlich. Für Änderungen sollte immer die Kernel/Config.pm angefasst werden.

Jetzt soll ein LDAP-Backend angebunden werden. Dazu kopieren wir einfach den Teil aus der Kernel/Config/Defaults.pm, der dafür verantwortlich und auskommentiert ist:


    $Self->{CustomerUser} = {
        Name => 'LDAP Backend',
        Module => 'Kernel::System::CustomerUser::LDAP',
        Params => {
            # ldap host
            Host => 'test.example',
            # ldap base dn
            BaseDN => 'ou=seas,o=csuh',
            # 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 => '',
            UserPw => '',
            # in case you want to add always one filter to each ldap query, use
            # this option. e. g. AlwaysFilter => '(mail=*)' or AlwaysFilter => '(objectclass=user)'
            AlwaysFilter => '',
            # if the charset of your ldap server is iso-8859-1, use this:
            # SourceCharset => 'iso-8859-1',
            # die if backend can't work, e. g. can't connect to server
            Die => 0,
            # Net::LDAP new params (if needed - for more info see perldoc Net::LDAP)
            Params => {
                port    => 389,
                timeout => 120,
                async   => 0,
                version => 3,
            },
        },
        # customer unique id
        CustomerKey => 'uid',
        # customer #
        CustomerID => 'mail',
        CustomerUserListFields => ['cn', 'mail'],
        CustomerUserSearchFields => ['uid', 'cn', 'mail'],
        CustomerUserSearchPrefix => '',
        CustomerUserSearchSuffix => '*',
        CustomerUserSearchListLimit => 250,
        CustomerUserPostMasterSearchFields => ['mail'],
        CustomerUserNameFields => ['givenname', 'sn'],
        # show now own tickets in customer panel, CompanyTickets
        CustomerUserExcludePrimaryCustomerID => 0,
        # add a ldap filter for valid users (expert setting)
        # CustomerUserValidFilter => '(!(description=gesperrt))',
        # admin can't change customer preferences
        AdminSetPreferences => 0,
        # cache time to live in sec. - cache any ldap queries
        CacheTTL => 0,
        Map => [
            # note: Login, Email and CustomerID needed!
            # var, frontend, storage, shown (1=always,2=lite), required, storage-type, http-link, readonly
            [ 'UserTitle',      'Title',      'title',           1, 0, 'var', '', 0 ],
            [ 'UserFirstname',  'Firstname',  'givenname',       1, 1, 'var', '', 0 ],
            [ 'UserLastname',   'Lastname',   'sn',              1, 1, 'var', '', 0 ],
            [ 'UserLogin',      'Username',   'uid',             1, 1, 'var', '', 0 ],
            [ 'UserEmail',      'Email',      'mail',            1, 1, 'var', '', 0 ],
            [ 'UserCustomerID', 'CustomerID', 'mail',            0, 1, 'var', '', 0 ],
            # [ 'UserCustomerIDs', 'CustomerIDs', 'second_customer_ids', 1, 0, 'var', '', 0 ],
            [ 'UserPhone',      'Phone',      'telephonenumber', 1, 0, 'var', '', 0 ],
            [ 'UserAddress',    'Address',    'postaladdress',   1, 0, 'var', '', 0 ],
            [ 'UserComment',    'Comment',    'description',     1, 0, 'var', '', 0 ],
            # this is needed, if "SMIME::FetchFromCustomer" is active
            # [ 'UserSMIMECertificate', 'SMIMECertificate', 'userSMIMECertificate',      0, 1, 'var', '', 0 ],
        ],
    };  

Einstellungen testen

Bevor man gleich das Kundenbackend in OTRS einträgt, sollte man die Einstellungen testen. Ich habe es nicht nur einmal erlebt, dass die Daten die mir als Zugangsdaten zum LDAP gegeben wurden nicht gepasst haben. Entweder war der LDAP-Server nicht erreichbar oder der User für die Verbindung hatte gar keine Rechte. Oder er war noch gar nicht angelegt.

Es gibt einige Tools, mit denen man die Einstellungen testen kann. Ich persönlich nutze ganz gerne die Kommandozeilentools.

otrsvm@otrs5s:~$ ldapsearch -H ldaps://ldap.jumpcloud.com:636 -x \
    -b "ou=Users,o=<id>,dc=jumpcloud,dc=com" \
    -D "uid=otrs_user,ou=Users,o=<id>,dc=jumpcloud,dc=com" -w "<passwd>"
# extended LDIF
#
# LDAPv3
# base <ou=Users,o=<id>,dc=jumpcloud,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# Users, <id>, jumpcloud.com
dn: ou=Users,o=<id>,dc=jumpcloud,dc=com
ou: Users
objectClass: organizationalUnit
objectClass: top

# otrs_user, Users, <id>, jumpcloud.com
# ... user information ...

Auf SourceForge gibt es das Tool OTRS ActiveDirectory config creator. Das habe ich allerdings noch nie genutzt, kann daher keine Aussage dazu treffen, wie gut das Tool ist.

Konfiguration anpassen

Nachdem die Einstellungen getestet wurden, können diese in die Konfiguration eingetragen werden.

Wird ein ActiveDirectory verwendet, müssen mehrere Sachen angepasst werden, weil die Standardattribute von denen im LDAP abweichen. Statt uid als UserLogin zu verwenden, muss z.B. sAMAccountName verwendet werden.

Weiterhin muss das Mapping angepasst werden. Dazu muss man sich überlegen, welche Eigenschaften eines Kunden sollen im OTRS genutzt werden. Das Beispiel-Mapping nennt nur die grundlegenden Stammdaten, aber eventuell möchte man noch die Mobilnummer anzeigen oder - gerade wenn es unternehmensinterne Kunden sind - die Abteilung und die Kostenstelle.

Wer vom Standardmapping abweichen will, muss sich als erstes die Attribute im LDAP raussuchen.

Für jedes Attribut wird eine Zeile im Mapping angelegt:

[ 'UserPhone',      'Phone',      'telephonenumber', 1, 0, 'var', '', 0 ],

Diese Angaben bedeuten:

  1. Attribut im CustomerUser-Objekt - z.B. zur Verwendung in Benachrichtigungen über <OTRS_CUSTOMER_DATA_UserPhone>
  2. Anzeige in der Oberfläche (wird übersetzt)
  3. Attribut im LDAP/AD
  4. Angabe, ob das Attribut angezeigt werden soll oder nicht
  5. Angabe, ob das Attribut ein Pflichtfeld ist
  6. Legt fest, ob das Attribut eine Zahl oder ein String ist
  7. Template für eine Verlinkung des Attributs (siehe auch [diesen Blogpost](https://blog.feature-addons.de/2017-03-23-callto-tel-link-in-kundendaten))
  8. Angabe, ob nur lesend auf das Attribut zugegriffen wird

Da auf LDAP-Backends nur lesend zugegriffen wird und keine Änderungen der Daten über OTRS möglich ist, sind die Angaben in den Spalten 5, 6 und 8 irrelevant.

JumpCloud

Für alle Entwickler: Um nicht ein eigenes LDAP installieren und warten zu müssen, habe ich mir einen kostenlosen Account bei JumpCloud einen kostenlosen Account geholt und ein paar Beispieldaten eingespielt.

Dann ist es einfach, in Demosystemen oder zu Testzwecken ein LDAP-Backend einzubinden.

LDAPS

Standardmäßig wird eine ungesicherte Verbindung zum LDAP aufgebaut. Wer eine Verbindung über SSL aufbauen möchte, kann das mit nur kleinen Änderungen erreichen.

Als Schema muss ldaps eingetragen und der Port muss angepasst werden. Standardmäßig ist der Port für ldaps der 636.

Der geändert Ausschnitt aus der Konfiguration:


    Params => {
        scheme  => 'ldaps',
        port    => 636,
        timeout => 120,
        async   => 0,
        version => 3,
    },

Zertifikate

Müssen Zertifikate angegeben werden, sind weitergehende Änderungen in der Konfiguration notwendig. Dazu ist es ganz praktisch, dass das LDAP-Authentifizierungsmodul von OTRS einige Parameter aus der Konfiguration direkt an das Modul Net::LDAP weitergibt.

Sobald das Schema ldaps eingetragen ist, können diese Parameter übergeben werden:

  • cafile
  • capath
  • clientcert
  • clientkey
  • ciphers
  • sslversion
  • sslserver

also z.B.


    Params => {
        scheme  => 'ldaps',
        port    => 636,
        timeout => 120,
        async   => 0,
        version => 3,
        clientcert => '/path/to/cert.pem',
        clientkey  => '/path/to/key.pem',
    },

Mehrere Backends nutzen

Möchte man nicht nur LDAP als Kundenbackend nutzen, sondern auch die Datenbank, dann ist das kein Problem. In OTRS kann man mehrere Kundenbackends eintragen - aktuell (OTRS 5.0.20) sind es bis zu 11 Backends. Wer mehr braucht, muss das an vielen Stellen im Code anpassen.

Aber ob die große Zahl an Kundendatenbackends sinnvoll ist, steht wieder auf einem anderen Blatt. Jedes Backend frisst natürlich etwas Performanz, da ggf. Daten über das Netzwerk geschoben werden, evtl. sind auch die LDAP-Hosts oder die Datenbanken nicht erreichbar.

Ich tendiere immer dazu, die Kundenbackends weitestgehend zusammenzufassen - wenn es geht.

Bei zwei Backends lohnt sich das Zusammenführen meist noch nicht, aber wenn es mal mehr als vier Backends werden, sollte man sich mal Gedanken dazu machen.

Die verschiedenen Backends werden durch eine fortlaufende Nummerierung unterschieden:


    $Self->{CustomerUser} = {
        Name => 'LDAP Backend',
        Module => 'Kernel::System::CustomerUser::LDAP',
        # weitere Parameter
    };

    $Self->{CustomerUser1} = {
        Name => 'OTRS DB Backend',
        Module => 'Kernel::System::CustomerUser::DB',
        # weitere Parameter
    };

    $Self->{CustomerUser2} = {
        Name => 'Supplier LDAP Backend',
        Module => 'Kernel::System::CustomerUser::LDAP',
        # weitere Parameter
    };

Authentifizierung

Bisher hat dieser Blogpost nur die Datenhaltung der Kundenbenutzer betrachtet. Wird das Kundenfrontend benutzt, muss ggf. noch die Authentifizierung über das LDAP bzw. über die Datenbank laufen. Auch hierfür gibt es eigene Konfigurationseinstellungen, die in der Kernel/Config.pmgemacht werden müssen.


    #Enable LDAP authentication for Customers / Users
    $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::LDAP';
    $Self->{'Customer::AuthModule::LDAP::Host'} = 'host.example.com';
    $Self->{'Customer::AuthModule::LDAP::BaseDN'} = 'ou=BaseOU,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'} = 'otrs_ldap';
    $Self->{'Customer::AuthModule::LDAP::SearchUserPw'} = 'PASSWORD';

    # Second auth-backend: The OTRS DB
    $Self->{'Customer::AuthModule1'}                       = 'Kernel::System::CustomerAuth::DB';
    $Self->{'Customer::AuthModule::DB::Table1'}            = 'customer_user';
    $Self->{'Customer::AuthModule::DB::CustomerKey1'}      = 'login';
    $Self->{'Customer::AuthModule::DB::CustomerPassword1'} = 'pw';

Genauso wie bei den Backends für die Kundenbenutzerdaten, kann man mehrere Authentifizierungsbackends angeben. Die Parameter, die zusammengehören, müssen auch den einheitlichen Suffix haben. So wie hier bei allen Parametern für die OTRS-Datenbank den Suffix 1 haben.

Welche Reihenfolge?!

Geht es um mehrere Backends stellt sich die Frage, welche Reihenfolge die Einträge haben sollten.

Das ist nicht ganz einfach pauschal zu beantworten. Ich würde mir Gedanken dazu machen, welche Backends am häufigsten benötigt werden und wie diese Backends angebunden sind. OTRS geht die Backends der Reihe nach durch, also zu erst CustomerUser, dann CustomerUser1, anschließend CustomerUser2 und so weiter.

Ich würde die langsamsten Backends ans Ende stellen - außer es ist ein Backend dabei, aus dem der Großteil der abgerufenen Kundendaten stammt. Dann würde ich das weiter nach vorne einsortieren (und schauen ob ich nicht an der Perfomanz etwas drehen kann).

Die Dokumentation zum Thema Kundenbenutzerbackends ist auf github zu finden: http://otrs.github.io/doc/manual/admin/stable/en/html/external-backends.html#customer-user-backend.

Permalink:

Archiv