Inhalt
In dieser Dokumentation möchte ich zeigen, wie man in dem Identity Governant Access (IGA) System "Midpoint" User nach LDAP überträgt.
Ich habe im Vorfeld folgendes dokumentiert:
- Installation eines leeren Midpointservers (IGA) via Podman (siehe Punkt 1)
- Installation eines LDAP Podman Servers (siehe Punkt 2)
- Installation eines Keyclock Podman Servers (siehe Punkt 3)
- Ein hr.csv Import in den Midpoint Server (siehe Punkt 4).
Hier, mit Punkt 5, beschreibe ich, wie ich diese User in meinen LDAP Server übertrage:
Inhaltstabelle:
- Inhalt
- LDAP Server starten
- Alle Services gleichzeitig starten mit Visual Studio Code
- Midpoint mit LDAP connecten
- Fazit
LDAP Server starten
Wie erwähnt, hatte ich in Punkt 1 beschrieben, wie man einen LDAP-Server erstmalig als Podman Container startet und den ersten User anlegt.
Nun starten wir diesen Server in einem neuen Bash Terminal erneut mit:
podman start -a ldap_server
Wir schauen, ob der erste User dort noch existiert. Dazu öffnen wir ein neues Terminal und geben dort ein:
podman exec -it ldap_server bin/bash
ldapsearch -x -H ldap://localhost:3389 -D "cn=Directory Manager" -w 1234 -b "dc=example,dc=com"
Der User sollte zu sehen sein:
Alle Services gleichzeitig starten mit Visual Studio Code
Es ist mühselig, die Server jeweils in einer Konsole zu starten. Ich habe ja auch noch den Midpoint-, Keycloak- und Nginx-Server im Gepäck.
Daher habe ich mir eine Task.json Datei im Ordner .vscode angelegt mit folgendem Inhalt:
{
"version": "2.0.0",
"tasks": [
{
"label": "Start All Services",
"dependsOn": [
"Midpoint Server",
"Midpoint Shell",
"Keycloak Server",
"LDAP Server",
"LDAP Shell",
"Nginx Server"
],
"problemMatcher": [],
"isBackground": true
},
{
"label": "Midpoint Server",
"type": "shell",
"command": "cd ${workspaceFolder}/midpoint && ./start_midpoint_server.sh",
"options": {
"cwd": "${workspaceFolder}/midpoint"
},
"presentation": {
"reveal": true,
"panel": "new",
"clear": true,
"title": "Midpoint Server"
},
"problemMatcher": [],
"isBackground": true
},
{
"label": "Midpoint Shell",
"type": "shell",
"command": "sleep 20 && cd ${workspaceFolder}/midpoint && ./start_midpoint_shell.sh",
"options": {
"cwd": "${workspaceFolder}/midpoint"
},
"presentation": {
"reveal": true,
"panel": "new",
"clear": true,
"title": "Midpoint Shell"
},
"problemMatcher": [],
"isBackground": true
},
{
"label": "Keycloak Server",
"type": "shell",
"command": "cd ${workspaceFolder}/keycloak && ./start_keycloak_server.sh",
"options": {
"cwd": "${workspaceFolder}/keycloak"
},
"presentation": {
"reveal": true,
"panel": "new",
"clear": true,
"title": "Keycloak Server"
},
"problemMatcher": [],
"isBackground": true
},
{
"label": "LDAP Server",
"type": "shell",
"command": "cd ${workspaceFolder}/ldap && ./start_ldap_server.sh",
"options": {
"cwd": "${workspaceFolder}/ldap"
},
"presentation": {
"reveal": true,
"panel": "new",
"clear": true,
"title": "LDAP Server"
},
"problemMatcher": [],
"isBackground": true
},
{
"label": "LDAP Shell",
"type": "shell",
"command": "sleep 20 && cd ${workspaceFolder}/ldap && ./start_ldap_client.sh",
"options": {
"cwd": "${workspaceFolder}/ldap"
},
"presentation": {
"reveal": true,
"panel": "new",
"clear": true,
"title": "LDAP Client"
},
"problemMatcher": [],
"isBackground": true
},
{
"label": "Nginx Server",
"type": "shell",
"command": "cd ${workspaceFolder}/nginx && ./start_nginx.sh",
"options": {
"cwd": "${workspaceFolder}/nginx"
},
"presentation": {
"reveal": true,
"panel": "new",
"clear": true,
"title": "Nginx"
},
"problemMatcher": [],
"isBackground": true
}
]
}
Wenn man nun das VSStudio Code neu startet, kann man mit Strg+Shift+p den Befehl "Run Tasks" eingeben und dann "Start All Services" anklicken. Als Ergebnis öffnen sich mehrere Shell Konsolen in denen die Server gestartet werden:
Midpoint mit LDAP connecten
Wir haben nun folgende Ziele:
- Wir wollen User aus LDAP in Midpoint einlesen (LDAP Import)
- Wir wollen diese User verändern und nach LDAP schreiben (Reconciliation)
- Wir wollen User, die aus HR kommen nach LDAP übertragen (HR.csv Import + Reconciliation nach LDAP)
1. LDAP User importieren via XML
Nun möchten wir die User von LDAP in Midpoint importieren. Dazu brauchen wir eine Ressourcendefinition mit einem Usermapping und einen Import Task.
1.1 Resourcendefinition laden
Das Usermapping übernehmen wir direkt mit in der XML Datei, die auch die Resourcendefinition erstellt.
Dazu klicken wir auf Resources/All Resources und dort das Import Symbol:
Dann importieren wir folgende Resourcedefinition (Quelle):
<?xml version="1.0" encoding="UTF-8"?>
<resource xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
xmlns:icfc="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/connector-schema-3"
xmlns:icfs="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/resource-schema-3"
xmlns:icfcldap="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/bundle/com.evolveum.polygon.connector-ldap/com.evolveum.polygon.connector.ldap.LdapConnector"
xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3"
oid="44444444-4444-4444-4444-000000000000">
<name>Local LDAP Server</name>
<description>Connection to the local LDAP server</description>
<connectorRef type="ConnectorType">
<filter>
<q:equal>
<q:path>connectorType</q:path>
<q:value>com.evolveum.polygon.connector.ldap.LdapConnector</q:value>
</q:equal>
</filter>
</connectorRef>
<connectorConfiguration>
<icfc:configurationProperties>
<icfcldap:host>host.docker.internal</icfcldap:host>
<icfcldap:port>3389</icfcldap:port>
<icfcldap:baseContext>dc=example,dc=com</icfcldap:baseContext>
<icfcldap:bindDn>cn=Directory Manager</icfcldap:bindDn>
<icfcldap:bindPassword>
<t:clearValue>1234</t:clearValue>
</icfcldap:bindPassword>
</icfc:configurationProperties>
</connectorConfiguration>
<schemaHandling>
<objectType>
<kind>account</kind>
<default>true</default>
<objectClass>inetOrgPerson</objectClass>
<auxiliaryObjectClass>posixAccount</auxiliaryObjectClass>
<attribute>
<ref>uid</ref>
<displayName>Username</displayName>
<outbound>
<source>
<path>$user/name</path>
</source>
</outbound>
<inbound>
<target>
<path>$user/name</path>
</target>
</inbound>
</attribute>
<attribute>
<ref>cn</ref>
<displayName>Full Name</displayName>
<outbound>
<source>
<path>$user/fullName</path>
</source>
</outbound>
<inbound>
<target>
<path>$user/fullName</path>
</target>
</inbound>
</attribute>
<attribute>
<ref>sn</ref>
<displayName>Last Name</displayName>
<outbound>
<source>
<path>$user/familyName</path>
</source>
</outbound>
<inbound>
<target>
<path>$user/familyName</path>
</target>
</inbound>
</attribute>
</objectType>
</schemaHandling>
<synchronization>
<objectSynchronization>
<enabled>true</enabled>
<correlation>
<q:equal>
<q:path>name</q:path>
<expression>
<path>$account/attributes/uid</path>
</expression>
</q:equal>
</correlation>
<reaction>
<situation>unlinked</situation>
<action>
<handlerUri>http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus
</action>
</reaction>
<reaction>
<situation>unmatched</situation>
<action>
<handlerUri>http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus
</action>
</reaction>
</objectSynchronization>
</synchronization>
</resource>
1.2 Usermapping ggf. anpassen
Die Usermappings wurden mit dem XML erstellt. Wir brauchen hier eigentlich nichts zu tun. Falls wir doch mal nachschauen oder etwas ändern wollen, geht das wie folgt: Wir finden die Mappings unter Resources/All Ressources/Local LDAP Server/Schema Handling/Object Types:
... Mappings:
Wenn man sie verändern will, muss links in den Namensfeldern noch Werte eingetragen werden. Ich habe einfach die Namen aus dem Ressource Attribut kopiert:
1.3 Import Task erstellen
Wir Klicken auf Server Tasks/All Tasks/New Task (Plus Symbol)/Import Task und füllen das Formular wie folgt aus:
So sieht der fertige Task aus:
1.4 Import Laufen lassen
Wir haben nun eine Resourcendefinition mit einem Usermapping und einen Importtask.
Wir starten nun den ersten Importlauf:
Die Ergebnisse des Imports stehen unter "Results" oder "Errors":
Wenn alles klappt, werden User als Accounts der Ressource zugefügt.
Sie sind damit aber sogenannte Schattenaccounts, die noch keinem User zugeordnet sind. Das könnte man rechts über den Knopf "Change Owner" erledigen, eleganter ist aber ein Reconciliation Task:
2. Reconcoliation Task erstellen und laufen lassen
Unter Server Tasks erstellen wir einen neuen Reconciliation Task:
Dieser importiert die LDAP User auch als User in Midpoint. D.h. es werden zuerst Accounts erstellt und dann User, die mit diesen Accounts verknüpft sind:
3. HR User Export nach LDAP
Viel spannender als LDAP User zu syncronisieren, ist natürlich, User, die wir mit einem HR Import erhalten haben, nach LDAP zu provisionieren.
Folgende Resourcendefinition (Quelle) baut eine Verbindung zum LDAP Server auf und ermöglicht eine Übertragung der User in dem Format, das der LDAP Server versteht:
<?xml version="1.0" encoding="UTF-8"?>
<resource oid="8a83b1a4-be18-11e6-ae84-7301fdab1d7c"
xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:t='http://prism.evolveum.com/xml/ns/public/types-3'
xmlns:ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance-3"
xmlns:icfs="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/resource-schema-3"
xmlns:icfc="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/connector-schema-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
xmlns:mr="http://prism.evolveum.com/xml/ns/public/matching-rule-3"
xmlns:cap="http://midpoint.evolveum.com/xml/ns/public/resource/capabilities-3">
<name>LDAP</name>
<description>
LDAP resource using a ConnId LDAP connector. It contains configuration
for use with OpenLDAP servers.
This is a sample used in the "Practical Identity Management with MidPoint"
book, chapter 4.
</description>
<connectorRef type="ConnectorType">
<filter>
<q:text>connectorType = "com.evolveum.polygon.connector.ldap.LdapConnector"</q:text>
</filter>
</connectorRef>
<connectorConfiguration
xmlns:icfc="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/connector-schema-3"
xmlns:icfcldap="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/bundle/com.evolveum.polygon.connector-ldap/com.evolveum.polygon.connector.ldap.LdapConnector">
<icfc:configurationProperties>
<icfcldap:port>3389</icfcldap:port>
<icfcldap:host>host.docker.internal</icfcldap:host>
<icfcldap:baseContext>dc=example,dc=com</icfcldap:baseContext>
<icfcldap:bindDn>cn=Directory Manager</icfcldap:bindDn>
<icfcldap:bindPassword><t:clearValue>1234</t:clearValue>icfcldap:bindPassword>
<icfcldap:passwordHashAlgorithm>SSHA</icfcldap:passwordHashAlgorithm>
<icfcldap:vlvSortAttribute>uid,cn,ou,dc</icfcldap:vlvSortAttribute>
<icfcldap:vlvSortOrderingRule>2.5.13.3</icfcldap:vlvSortOrderingRule>
<icfcldap:operationalAttributes>memberOf</icfcldap:operationalAttributes>
<icfcldap:operationalAttributes>createTimestamp</icfcldap:operationalAttributes>
</icfc:configurationProperties>
</connectorConfiguration>
<schemaHandling>
<objectType>
<kind>account</kind>
<displayName>Normal Account</displayName>
<default>true</default>
<delineation>
<objectClass>inetOrgPerson</objectClass>
</delineation>
<attribute>
<ref>dn</ref>
<displayName>Distinguished Name</displayName>
<limitations>
<minOccurs>0</minOccurs>
</limitations>
<outbound>
<source>
<path>$focus/name</path>
</source>
<expression>
<script>
<code>
basic.composeDnWithSuffix('uid', name, 'ou=users,dc=example,dc=com')
</code>
</script>
</expression>
</outbound>
</attribute>
<attribute>
<ref>entryUUID</ref>
<displayName>Entry UUID</displayName>
</attribute>
<attribute>
<ref>cn</ref>
<displayName>Common Name</displayName>
<limitations>
<minOccurs>0</minOccurs>
</limitations>
<outbound>
<source>
<path>$focus/fullName</path>
</source>
</outbound>
</attribute>
<attribute>
<ref>sn</ref>
<displayName>Surname</displayName>
<limitations>
<minOccurs>0</minOccurs>
</limitations>
<outbound>
<source>
<path>$focus/familyName</path>
</source>
</outbound>
</attribute>
<attribute>
<ref>givenName</ref>
<displayName>Given Name</displayName>
<outbound>
<source>
<path>$focus/givenName</path>
</source>
</outbound>
</attribute>
<attribute>
<ref>uid</ref>
<displayName>Login Name</displayName>
<outbound>
<strength>weak</strength>
<source>
<path>$focus/name</path>
</source>
</outbound>
</attribute>
<attribute>
<ref>description</ref>
<outbound>
<strength>weak</strength>
<expression>
<value>Created by midPoint</value>
</expression>
</outbound>
</attribute>
<activation>
<administrativeStatus>
<outbound/>
</administrativeStatus>
</activation>
<credentials>
<password>
<outbound/>
</password>
</credentials>
</objectType>
</schemaHandling>
</resource>
Die Test-Connection der Resource hat bei mir funktioniert:

Danach bin ich auf einen der von HR importierten Usereinträge gegangen:

Dort klickte ich auf Assigenments und erstellte ein neues:

Dort klickte ich auf Resource:

und fügte dort meine LDAP Reconcile Resource zu:

Das Ganze musste natürlich gespeichert werden:

Damit wird sofort der LDAPadd Befehl im Hintergrund ausgelöst. Das Ergebnis kann mit
ldapsearch -x -H ldap://localhost:3389 -D "cn=Directory Manager" -w 1234 -b "dc=example,dc=com"
gesehen werden. Wir finden nun den HR User im LDAP wieder:

Das ist natürlich manuelle Arbeit, die für jeden User aus HR gemacht werden müsste. Das geht sicherlich auch automatisiert, ist aber hier nicht das Thema.
Fazit
Wir sind nun in der Lage User aus HR im csv Format zu importieren und diese nach LDAP zu übertragen.
Als nächstes möchte ich eine rudimentäre Nginx-Applikation z.B. über OpenID Connect an den LDAP Server anbinden. Ziel ist, dass ein User, der mit der HR Datei geliefert wurde, sich an der Web-App anmelden kann.
So Stay tuned,
Achim Mertens