-
AutorBeiträge
-
-
17. Juni 2026 um 15:09 Uhr - Views: 170 #41833
Hallo zusammen!
Wir haben unser OTOBO 11 Docker via OpenIDConnect an Entra angebunden. Agent und Customer Login. Das hat soweit mittels Hilfe aus dem FAQ und Google Suche auch geklappt :-)
Derzeit haben wir aber die Customeruser noch via LDAP Sync (genau wie ehem. unser OTRS) an unser lokales AD angebunden und hier ein „wildes“ Mapping mit zig zusätzlichen Feldern.
Also via Module => ‚Kernel::System::CustomerUser::LDAP‘,Hier stellt sich mir die Frage und ich habe dazu nichts im Forum oder der Defaults.pm gefunden:
Kann man das auch über Entra beziehen, so dass kein lokales AD mehr nötig ist? Die Felder / ExtensionAttibutes haben wir soweit bereits ins Entra gesynct.Bei OTRS scheint es zu geben:
Kernel::System::CustomerUser::OIDCBei OTOBO habe ich dazu – wie gesagt – nichts gefunden. Vielleicht hat ja jemand sowas schon mal probiert oder es ist in Planung?
Danke und VG,
Sascha -
17. Juni 2026 um 15:50 Uhr #41835
Hi Sascha,
man kann das Auth für CustomerUser auch über OIDC abbilden, aber man braucht dann noch einen Sync für die Daten. Das ist anders als bei den Agenten, deren Daten per Map komplett aus dem OIDC kommen können.
Der Hintergrund ist die Art der Datenverarbeitung. Der Agent meldet sich an und hat dann frische Daten für seine Session. Die Daten der CustomerUser werden verarbeitet ohne das sich dieser anmeldet. OTOBO muss die Daten hier zum beliebigen Zeitpunkt anfragen können.
Beispielkonfiguration, wie man das Auth für CustomerUser einrichtet, findest du in der Defaults.pm: https://github.com/RotherOSS/otobo/blob/rel-11_0/Kernel/Config/Defaults.pm#L1560
Viel Spaß mit deinem OTOBO!
-
17. Juni 2026 um 16:10 Uhr #41838
Achso, also geht das mit dem CustomerUser Backend über OIDC dann also gar nicht?
Weil es geht nicht um den „CustomerAuth“, das funktioniert via OIDC. Es geht um die befüllung der Tabelle CustomerUser, was wir jetzt noch über LDAP „Module => ‚Kernel::System::CustomerUser::LDAP‘,“ machen…
-
17. Juni 2026 um 16:23 Uhr #41839
Meines Wissens nach, ist OIDC ist eine Authentifizierungsschicht und kein Verziechnisdienst, zumindest von der Konzeption her.
Hast du eine Quelle die sagt wie man beliebige Nutzer aus einer OIDC-Schnittstelle abfragen kann? Ich wäre hier interessiert.
-
17. Juni 2026 um 16:30 Uhr #41840
Leider nicht wirklich.
Würde gerne auf die LDAP Anbindung für das CustomerUser Backend verzichten und das auch komplett über Entra machen…
Das einzige, was ich dazu finden kann, ist etwas bei OTRS:
Kernel::System::CustomerUser::OIDC – CustomerUser backend for OIDC
-
18. Juni 2026 um 10:31 Uhr #41845
Hallo Sacha,
EntraID bietet noch mehr Schnittstellen als OIDC. Hier käme insbesondere die Graph API in Frage. Bisher scheint das aber Nutzern nicht wichtig genug um hier aktiv zu werden. OTOBO hat noch keine Unterstützung für diese Schnittstelle. Vielleicht ist das Interesse ja mal groß genug, dass jemand die durch die Entwicklung entstehenden Aufwände trägt. Bis dahin vertrauen wir auf LDAP und SQL für die Nutzerdaten.
-
18. Juni 2026 um 13:00 Uhr #41848
Hallo Zusammen,
ich habe mal bisschen Recheriert und auch die KI dazu befragt. Hier das Ergebnis:
Vorab, über den in Weg B beschribenen Prozess könnte man sicherlich was scripten.Wenn Sie über OpenID Connect (OIDC) nicht nur das Login absichern, sondern auch das komplette Kundenverzeichnis im Hintergrund abgleichen (synchronisieren) möchten (z. B. damit Agenten beim Erstellen eines Telefontickets sofort alle OIDC-Kunden per Autovervollständigung finden), stehen Sie vor einer technischen Hürde: OIDC ist ein reines Authentifizierungsprotokoll und bietet von sich aus keine Such- oder Abfragefunktion für Verzeichnisse. [1, 2]
Um dies in OTOBO elegant zu lösen, kombiniert man das OIDC-Login mit einer Just-in-Time-Provisionierung (Daten werden beim Login in die lokale OTOBO-Datenbank geschrieben) oder nutzt ein Skript, das die Microsoft Graph API abfragt. [1]
Hier sind die zwei bewährten Wege, um den Abgleich in OTOBO zu realisieren:Weg A: Just-in-Time Provisionierung (Die Standard-OIDC-Methode)
Bei dieser Methode werden die Benutzerdaten synchronisiert, sobald sich ein Kunde das erste Mal per OIDC einloggt. Das OTOBO-Kunden-Backend wird dafür auf die lokale Datenbank (Kernel::System::CustomerUser::DB) umgestellt. OTOBO zieht sich beim Login alle Attribute aus dem Entra ID-Token und legt den Kunden lokal an bzw. aktualisiert ihn bei jedem Folge-Login. [1, 2, 3]
Vorteil: Extrem performant, keine Zusatzskripte nötig, Daten sind immer absolut up-to-date.
Nachteil: Ein Kunde taucht in der Agenten-Suche erst auf, nachdem er sich mindestens einmal am OTOBO-Kundenportal angemeldet hat. [1]Konfiguration in der Kernel/Config.pm:
perl
# 1. OIDC Authentifizierung für das Kundenportal aktivieren
$Self->{‚Customer::AuthModule‘} = ‚Kernel::System::CustomerAuth::OpenIDConnect‘;
$Self->{‚Customer::AuthModule::OpenIDConnect‘} = {
URL => ‚https://microsoftonline.com{ihre-tenant-id}/v2.0‘,
ClientID => ‚IHRE_CLIENT_ID‘,
ClientSecret => ‚IHR_CLIENT_SECRET‘,
Scope => [‚openid‘, ‚profile‘, ‚email‘],
UserIDClaim => ‚preferred_username‘, # Entra-Loginname (E-Mail)
};# 2. AUTOMATISCHER ABGLEICH (Just-in-Time Provisionierung in die DB)
$Self->{‚Customer::AuthModule::OpenIDConnect‘}->{ProvisionCustomerUser} = 1;# Zuordnung: Welcher Entra-Claim wandert in welches OTOBO-Datenbankfeld
$Self->{‚Customer::AuthModule::OpenIDConnect‘}->{UserMap} = {
‚UserFirstname‘ => ‚given_name‘,
‚UserLastname‘ => ‚family_name‘,
‚UserEmail‘ => ‚email‘,
‚UserCustomerID‘ => ‚email‘, # Oder ein anderes Feld für die Firmenzuordnung
};# 3. Das Kunden-Backend liest/sucht nun in dieser lokalen Datenbank
$Self->{CustomerUser} = {
Name => ‚Lokale DB (Synchronisiert via OIDC)‘,
Module => ‚Kernel::System::CustomerUser::DB‘,
Params => {
Table => ‚customer_user‘,
},
CustomerKey => ‚login‘,
CustomerID => ‚customer_id‘,
CustomerUserListFields => [‚first_name‘, ‚last_name‘, ‚email‘],
CustomerUserSearchFields => [‚login‘, ‚first_name‘, ‚last_name‘, ‚email‘],
CustomerUserPostMasterSearchFields => [‚email‘],
CustomerUserNameFields => [‚first_name‘, ‚last_name‘],
Map => [
[ ‚UserFirstname‘, ‚Firstname‘, ‚first_name‘, 1, 1, ‚var‘, “, 0 ],
[ ‚UserLastname‘, ‚Lastname‘, ‚last_name‘, 1, 1, ‚var‘, “, 0 ],
[ ‚UserLogin‘, ‚Username‘, ‚login‘, 1, 1, ‚var‘, “, 0 ],
[ ‚UserEmail‘, ‚Email‘, ‚email‘, 1, 1, ‚var‘, “, 0 ],
[ ‚UserCustomerID‘, ‚CustomerID‘, ‚customer_id‘, 0, 1, ‚var‘, “, 0 ],
],
};Weg B:
Vollständiger Vorab-Abgleich via Microsoft Graph API (Empfohlen für Agenten-Suche)
Wenn Sie zwingend alle Mitarbeiter/Kunden sofort im System durchsuchbar machen möchten, ohne dass diese sich je eingeloggt haben, müssen Sie die Benutzerdaten aktiv aus der Cloud abrufen. Da OTOBO (und OTRS) nativ keinen „Graph-API-Verzeichnis-Sync“ im CustomerUser-Backend eingebaut haben, nutzt man hierfür ein automatisiertes Synchronisations-Skript. [1]Ablauf:
Das OTOBO Kunden-Backend verbleibt (wie in Weg A) auf der lokalen Datenbank (Kernel::System::CustomerUser::DB).
Sie geben der App-Registrierung in Microsoft Entra ID unter API-Berechtigungen das Anwendungsrecht (Application Permission) User.Read.All für die Microsoft Graph API und stimmen als Admin zu.
Ein kleines Python- oder Bash-Skript läuft als stündlicher Cronjob auf dem OTOBO-Server. [1, 2, 3]Beispiel für das Sync-Skript (Konzeptidee für Cronjob):
Das Skript holt per REST-API die Benutzer ab und schreibt sie direkt in die OTOBO-Tabelle customer_user:python
import requests
import database_connector # Ihre OTOBO DB-Verbindung# 1. Token von Entra ID holen
token_url = „https://microsoftonline.com{tenant_id}/oauth2/v2.0/token“
data = {
‚grant_type‘: ‚client_credentials‘,
‚client_id‘: ‚IHRE_CLIENT_ID‘,
‚client_secret‘: ‚IHR_CLIENT_SECRET‘,
’scope‘: ‚https://microsoftonline.com‘
}
token = requests.post(token_url, data=data).json()[‚access_token‘]# 2. Benutzer aus Entra ID abfragen
headers = {‚Authorization‘: f’Bearer {token}‘}
users = requests.get(‚https://microsoftonline.com‘, headers=headers).json()# 3. In OTOBO-Datenbank spiegeln
for user in users[‚value‘]:
# SQL-Logik: INSERT INTO customer_user … ON DUPLICATE KEY UPDATE …
passWir nutzen auch Entra ID, haben aber für die Kundenbenutzer aktuell auch nicht den Bedarf.
Gruß Marcel
-
18. Juni 2026 um 13:58 Uhr #41849
Weg A ist ja der Weg, der für Agenten gegangen wird.
Nachteil von Weg A ist zusätzlich, dass die Daten auch immer so alt sind wie das letzte Login war.
Die fehlende Praktikabilität ist der Grund warum das aktuell nicht für CustomerUser implementiert ist.Weg B geht eben gegen die Graph API. Hier zwei Optionen:
1. Sync in die DB von Aussen
2. Inline sync als native OTOBO SchnittstelleIch kann mir vorstellen, dass Option 1 schlecht skaliert. Wenn ich stündlich 10.000 User über die GraphAPI ziehe, bin ich mir unklar über evtl. Rate Limits. Für eine kleine Anzahl an Datensätzen sicher ein probater Weg. Man muss sicher hier noch gucken wie man CustomerUser handhaben will, die zwar in der DB sind aber nicht mehr im EntraID und so weiter…
-
18. Juni 2026 um 14:45 Uhr #41850
Hallo Arnold,
man könnte sicher im AzureAD / Entra ein Flag setzen, dass nur die User mit diesem Flag synchronisiert werden. Oder besser noch über eine AzureAD Gruppe „Otobo_CustomerUser“ die dann nur die bestimmten User enthält, die verarbeitet werden sollen.
Das Script würde dann so in etwa aussehen.
#————————————————
import requests
# 1. Token von Microsoft Entra ID holen
tenant_id = „IHR_TENANT_ID“
token_url = f“https://microsoftonline.com{tenant_id}/oauth2/v2.0/token“token_data = {
„grant_type“: „client_credentials“,
„client_id“: „IHRE_CLIENT_ID“,
„client_secret“: „IHR_CLIENT_SECRET“,
„scope“: „https://microsoft.com“
}token_response = requests.post(token_url, data=token_data).json()
token = token_response.get(„access_token“)# 2. Mitglieder der Gruppe „otobo-customer“ abfragen
# ERSETZEN SIE DIESE ID MIT DER OBJEKT-ID IHRER ENTRA-GRUPPE
GROUP_ID = „IHRE_AZURE_AD_GRUPPEN_OBJEKT_ID“# Endpunkt für Gruppenmitglieder (filtert automatisch auf Direktmitglieder)
graph_url = f“https://microsoft.com{GROUP_ID}/members“
headers = {„Authorization“: f“Bearer {token}“}
users_response = requests.get(graph_url, headers=headers).json()
users = users_response.get(„value“, [])# 3. In OTOBO spiegeln via REST API
otobo_url = „https://ihr-otobo-system.de“
otobo_headers = {
„Content-Type“: „application/json“,
„X-OTOBO-API-Key“: „IHR_OTOBO_API_KEY“
}for user in users:
# Wichtig: Der /members Endpunkt liefert verschiedene Objekttypen (z.B. auch Gruppen).
# Wir filtern hier explizit so, dass nur Benutzer-Objekte verarbeitet werden.
if user.get(„@odata.type“) == „#microsoft.graph.user“:
customer_data = {
„UserLogin“: user.get(„userPrincipalName“),
„UserFirstname“: user.get(„givenName“) or „Vorname“,
„UserLastname“: user.get(„surname“) or „Nachname“,
„UserEmail“: user.get(„mail“) or user.get(„userPrincipalName“),
„UserCustomerID“: user.get(„mail“) or user.get(„userPrincipalName“),
„ValidID“: 1
}# Senden an OTOBO
response = requests.post(otobo_url, json=customer_data, headers=otobo_headers)
print(f“Synchronisiert: {customer_data[‚UserLogin‘]} – Status: {response.status_code}“)#————————————————
Gruß Marcel
-
18. Juni 2026 um 14:54 Uhr #41851
oder hier mit Bereinigung bzw. Deaktivierung der Customer User aus Otobo
import requests
def azure_to_otobo_sync():
print(„Starte Synchronisation und Bereinigung…“)tenant_id = „IHR_TENANT_ID“
token_url = f“https://microsoftonline.com{tenant_id}/oauth2/v2.0/token“token_data = {
„grant_type“: „client_credentials“,
„client_id“: „IHRE_CLIENT_ID“,
„client_secret“: „IHR_CLIENT_SECRET“,
„scope“: „https://microsoft.com“
}try:
# 1. Token von Azure AD holen
token_response = requests.post(token_url, data=token_data).json()
token = token_response.get(„access_token“)# 2. Aktive Gruppenmitglieder aus Azure AD abfragen
GROUP_ID = „IHRE_AZURE_AD_GRUPPEN_OBJEKT_ID“
graph_url = f“https://microsoft.com{GROUP_ID}/members“
headers = {„Authorization“: f“Bearer {token}“}
users_response = requests.get(graph_url, headers=headers).json()
azure_users = users_response.get(„value“, [])# Set für schnellen Abgleich erstellen (enthält alle gültigen Logins)
active_azure_logins = set()# OTOBO API Konfiguration
otobo_base_url = „https://ihr-otobo-system.de“
otobo_headers = {„Content-Type“: „application/json“, „X-OTOBO-API-Key“: „IHR_OTOBO_API_KEY“}# 3. Azure AD User anlegen oder aktualisieren
for user in azure_users:
if user.get(„@odata.type“) == „#microsoft.graph.user“:
login = user.get(„userPrincipalName“)
active_azure_logins.add(login)customer_data = {
„UserLogin“: login,
„UserFirstname“: user.get(„givenName“) or „Vorname“,
„UserLastname“: user.get(„surname“) or „Nachname“,
„UserEmail“: user.get(„mail“) or login,
„UserCustomerID“: user.get(„mail“) or login,
„ValidID“: 1 # In Azure vorhanden = Aktiv in OTOBO
}# Senden an OTOBO (erstellt oder reaktiviert den User)
requests.post(otobo_base_url, json=customer_data, headers=otobo_headers)print(f“{len(active_azure_logins)} aktive Benutzer aus Azure AD verarbeitet.“)
# 4. Bereinigung: OTOBO-User finden, die NICHT mehr in Azure AD sind
search_payload = {„Search“: „*“}
search_url = f“{otobo_base_url}Search“otobo_users_response = requests.post(search_url, json=search_payload, headers=otobo_headers)
if otobo_users_response.status_code == 200:
otobo_users = otobo_users_response.json().get(„CustomerUserList“, {})for otobo_login, otobo_email in otobo_users.items():
# Wenn der OTOBO-User nicht in der aktuellen Azure-Gruppe ist: Deaktivieren!
if otobo_login not in active_azure_logins:
deactivate_data = {
„UserLogin“: otobo_login,
„ValidID“: 2 # 2 entspricht im OTOBO-Standard „ungültig“
}
update_url = f“{otobo_base_url}Update“
res = requests.post(update_url, json=deactivate_data, headers=otobo_headers)
if res.status_code == 200:
print(f“Benutzer deaktiviert (nicht mehr in Azure): {otobo_login}“)
else:
print(„Hinweis: Bestehende OTOBO-Kunden konnten für den Inaktivitäts-Abgleich nicht ausgelesen werden.“)print(„Synchronisations- und Bereinigungszyklus erfolgreich beendet.“)
except Exception as e:
print(f“Fehler während des Abgleichs: {e}“)# Einmalige Ausführung beim Skriptaufruf
if __name__ == „__main__“:
azure_to_otobo_sync() -
18. Juni 2026 um 15:01 Uhr #41852
Oh da bin ich gespannt. Sollte jemand mal dieses Script einsetzten und GH Repo dazu anlegen, wäre ich an Erfahrungen interessiert.
-
19. Juni 2026 um 8:47 Uhr #41859
Hallo Arnold,
hab eben mal etwas probiert. Es wird so aber nicht funktionieren, weil es für die Customer User keine Webservice Operationen gibt.
Gruß Marcel
-
19. Juni 2026 um 10:14 Uhr #41879
Hi Marcel,
ich muss gestehen das Skript nicht gelesen zu haben, sondern nahm an, dass du den ursprünglichen Plan verfolgst, die CustomerUser in die Datenbank zu schreiben. Entweder in die OTOBO-Datenbank direkt oder eine externe (die kann man ja auch anbinden).
-
22. Juni 2026 um 9:06 Uhr #41901
Hallo Arnold,
wir selbst benötigen das ja auch niht, sondern eher der Ersteller.
Du hast recht, wenn man es über eine externe DB (Mysql/MariaDB) realisiert, ist das natürlich einfacher.
Mal schauen, ob ich diese Woche dazu komme.
Gruß Marcel
-
-
AutorBeiträge
- Du musst angemeldet sein, um auf dieses Thema antworten zu können.
