×

 
Neue Version vom Zimbra LDAP Connector

27.05.2025 - Robert Siedl

Vor einigen Jahren haben wir den Siedl-Zimbra-LDAP Connector (Projektname: sinbra) entwickelt.

Mit dem Konnektor werden Mailaccounts von Usern, Gruppen oder Verteilerlisten von einem Verzeichnisdienst wie openLDAP, Univention Corporate Server oder Active Directory AD in Zimbra synchronisiert.

Dies hat den großen Vorteil, dass

1. die Administration zentral im Verzeichnisdienst bzw. im Identity und Access Management (IAM) erfolgt und
2. die Benutzer für die Anmeldung am Zimbra Service automatisch das Kennwort vom Verzeichnisdienst verwenden bzw. die Authentifizierung über Single-Sign-on (SSO) ermöglicht

Da wir viele Migrationen von Microsoft Exchange Servern zu Zimbra durchführen, haben wir den Siedl-Zimbra-LDAP Connector um ein neues großes Feature erweitert: dynamische Expressions in der Config (Lob und Dank an unseren Developer Geri!).


Was sind die neuen Expressions?
Bei den supporteten Config Einstellungen können nun statt Attributsnamen python-like Expressions verwendet werden, die beim Mappen auf das LDAP-Objekt angewendet werden. Im Gegensatz zu den Templates bieten diese wesentlich mehr Möglichkeiten, da hier einzelne Schritte nicht mehr mit Regex aus der Eingabe geparst werden, sondern der Python eigene Code-Parser verwendet. Die möglichen, verwendeten Funktionen werden begrenzt, um die Möglichkeit, Schabernack zu treiben, zu verringern. Als "Variablen" können dabei die LDAP-Attribute verwendet werden, wobei Attribute die im Schema nicht als Single-Value gekennzeichnet sind als Liste übergeben werden (auch wenn diese nur 1 Element beinhalten). 

Achtung: Viele Attribute von denen man glauben würde, dass sie Single-Value sind, sind es in Wirklichkeit nicht (z.B. uid, sn, ...). Mit der Test Funktion (siehe unten) kann das relativ einfach herausgefunden werden!

Welche Funktionen gibt es derzeit?
Typ: bytes
- base64 -> Encoded die Daten als Base64

Typ: string:
- format -> Python String Formatierungs Funktion
- html_encode -> Ersetzt non-ascii Zeichen mit HTML Escape Sequenzen
- lower -> Konvertierung zu Kleinbuchstaben
- match(pattern, flags='') -> Führt eine Regex am String aus und gibt das Match Objekt zurück, Flags ist ein String mit einer oder mehreren Regex Flags (z.B. i für Case-Insensitive)
- replace(x, y) -> Ersetzt x mit y
- split -> Teilt den String in eine Liste
- sub(pattern, replacement, count=0, flags='') -> Wie replace, aber mit Regex Matching
- upper -> Konvertierung zu Großbuchstaben

Typ: list:
- each -> Führt die angegebene Sub-Expression für alle Listenelemente aus, wobei das jeweilige Element mit _ referenziert werden kann, und ersetzt das Element mit dem Ergebnis der Sub-Expression
- join(x) -> Fügt alle Listenelemente zu einem String zusammen, mit x als Trennzeichen
- where -> wie each, aber ersetzt das Element nicht, sondern entfernt dieses, wenn das Ergebnis der Sub-Expression False~ish ist

Die Expression ist vollständig mit bestehenden Configs kompatibel (der bisherige Attributsname ist auch eine Expression, die den entsprechenden Wert zurück gibt).

Für die Kompatibilität mit bestehenden Configs wurde aber folgender Sonderfall eingebaut:
Einstellungen, die einzelne Werte erfordern (z.B. die Primäre Adresse) akzeptieren auch eine Liste mit einem einzelnen Element. Sprich, die Rückwärtskompatibilität ist nur dann nicht gegeben, falls aus irgendeinem Grund ein Multi-Value Attribut mit mehreren Werten für eine Single-Value Config Option verwendet wurde. 

Unser initialer Anwendungsfall:
Microsoft Exchange speichert die Adressen eines Benutzers im Attribut "proxyAddresses", wobei die primäre Adresse mit dem Prefix "SMTP:" gekennzeichnet ist und die Alias Adressen mit "smtp:".
Das war bisher so nicht abbildbar, da der LDAP-Connector erwartet hat, dass die Primäre Adresse und Alias Adressen in 2 separaten Attributen zu finden sind, und diese als Inhalt ausschließlich die Adressen haben.
Mit den neuen Expressions lässt sich der Inhalt des Attributes nun filtern & umwandeln, und das Ergebnis wird dann schlussendlich verwendet:

email_attr = proxyAddresses.where(_.match('^SMTP:')).each(_.sub('^SMTP:',''))
Dabei wird jeder Wert der proxyAddresses auf den Prefix "SMTP:" geprüft, und Dieser bei jedem entfernt.

Wo können diese Expressions verwendet werden?
Expressions sind vorerst an diesen Stellen in der Config implementiert:
[DOMAIN] -> name_attr
[USER] -> email_attr, alias_attr, image_attr
[RESOURCE] -> email_attr, alias_attr
[GROUP] -> email_attr, alias_attr
[DLIST] -> email_attr, alias_attr

Außerdem gibt es bei sämtlichen Mappings den neuen Parsing Typ "x:", der es ermöglicht die Expressions zu verwenden. In Templates sind diese (derzeit) nicht implementiert, da die Expressions bereits alleine mehr Möglichkeiten bieten als Templates.

Wie können die Expressions getestet werden?
Es gibt einen neuen Sub-Command beim sinbra Script, der das ermöglicht.

Die Parameter sind:
sinbra test-expression <ldap-filter> <expression>

Bei "ldap-filter" kann auch der Name einer Config Section angegeben werden (z.B. user, group, ...), dann wird der bei "filter" hinterlegte Filter verwendet.
Wenn der Filter mehrere Objekte zurückgibt, wird die Expression für jedes davon getestet.


Beispiel einer Expression, die eine Email-Adresse aus Vor- & Nachname und der Domain-Base eines Benutzers zusammenbaut:

Expression Zimbra LDAP Connector

Wie wurde das ganze Implementiert?
Die angegebene Expression wird mit dem Python Code-Parser in einen ast (Syntax Tree) ausgewertet (aber nicht ausgeführt), und dieser dann Schritt für Schritt im Code abgearbeitet. Die Expressions sehen daher aus wie Python-Codes (und stimmen zum Großteil auch damit überein), sind es aber nicht wirklich.

Inwiefern weichen diese vom Python-Code ab?
Die Expressions sollten Null-Safe sein. Sprich: Funktionsaufrufe usw. auf Objekte, die keinen Wert besitzen, lösen keinen Fehler aus. Es gibt einige Funktionen, deren "Parameter" eine Sub-Expression ist, die dann ausgewertet wird (z.B. bei den Funktionen each & filter bei Listen). Im Bezug auf Python Code könnt ihr euch das wie eine lambda Funktion vorstellen. Da die Auswertung durch viele rekursive Funktionsaufrufe passiert, kann es sein dass der LDAP-Connector bei komplexen Expressions (vermutlich mit mehreren hundert verschachtelten Aufrufen) mit einem Stack Overflow abstürzt...

Welche Python Syntax-Features sind nicht supported?
- Alles, was nicht Teil einer Python-Expression ist (Funktionsdefinitionen, Loops, ...)
- Setzen von Variablen
- Lambda Funktionen
- Sämtliche Sequenzen außer Listen
- List-Comprehension (Lässt sich auch mit each & where umsetzen)
- Parameter Expansion (*x, **x)

Wir werden den Siedl Zimbra LDAP Connector zukünftig als Open Source Projekt online stellen. Nähere Informationen dazu folgen noch.

Bei Interesse oder Fragen schickt uns einfach eine e-Mail an support@siedl.net .

Liebe Grüße,

Robert

 

Beitrag drucken
Grafik Person

Für Fragen steht Ihnen
unser Team zur Verfügung

Grafik Briefumschlag

office@siedl.net

Grafik Telefon

+43 2732 71545-0

Facebook-Logo

Unsere Facebook-Seite

Grafik Werkzeug

Teamviewer Support

 
 

 

Siedl Networks GmbH

Dr.-Franz-Wilhelm-Straße 2
3500 Krems an der Donau

+43 2732 71545-0
office@siedl.net
support@siedl.net
 

Unsere Bürozeiten:

Montag bis Freitag:
08:00 Uhr - 12:00 Uhr
13:00 Uhr - 16:45 Uhr