{"id":1156,"date":"2024-03-24T17:54:05","date_gmt":"2024-03-24T15:54:05","guid":{"rendered":"https:\/\/sven-seeberg.de\/wp\/?p=1156"},"modified":"2025-04-02T16:46:30","modified_gmt":"2025-04-02T14:46:30","slug":"migrating-from-univention-corporate-server-to-sambakeycloak","status":"publish","type":"post","link":"https:\/\/sven-seeberg.de\/wp\/?p=1156","title":{"rendered":"Migrating from Univention Corporate Server to Samba and Keycloak"},"content":{"rendered":"\n<p>In the past I used the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Univention_Corporate_Server\">Univention Corporate Server<\/a> for Identity Management in some organizations. However, I find that UCS is relatively huge and I nowadays I prefer to operate a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Samba_(software)\">Samba<\/a> server in combination with <a href=\"https:\/\/en.wikipedia.org\/wiki\/Keycloak\">Keycloak<\/a>, because it is easier to integrate into <a href=\"https:\/\/en.wikipedia.org\/wiki\/Orchestration_(computing)\">server orchestration tools<\/a>. Also, Keycloak provides sufficient functionality to manage users within the Samba Active Directory. It took me quite some time to figure out how to migrate the data cleanly. The goal is to migrate the data into clean Active Directory structures. I only want to migrate the username, sn, givenName, displayName and mail attributes while keeping the objectUUID. Also, group memberships should be migrated.<\/p>\n\n\n\n<p>One major caveat was to import the entryUUID of UCS into the objectUUID attribute of Samba. samba-tool has no parameter to set the objectGUID for a new user. A possible workaround is to use ldbmodify to import the user objects first.  ldbmodify is available in the ldb-tools package on Debian based distributions.<\/p>\n\n\n\n<p>The import assumes that the Samba server has already been provisioned with<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>samba-tool domain provision<\/code><\/pre>\n\n\n\n<p>The following script can be used to export the data in 2 files:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\nUIDS=$(slapcat -a \"(mail=*)\" | grep uid: | sed \"s\/uid: \/\/\")\n\nwhile IFS= read -r USERUID; do\n\techo \"Exporting '$USERUID'\"\n\tUSER_DATA=$(slapcat -a \"(uid=$USERUID)\")\n\tUSER_DN=$(echo \"$USER_DATA\" | grep \"dn: \" | sed \"s\/dn: \/\/\")\n\tUSER_GUID=$(echo \"$USER_DATA\" | grep \"entryUUID: \" | sed \"s\/entryUUID: \/\/\")\n\tUSER_MAIL=$(echo \"$USER_DATA\" | grep -E \"^mail:\" | sed \"s\/^mail:\/\/\")\n\tUSER_FIRST_NAME=$(echo \"$USER_DATA\" | grep \"givenName:\" | sed \"s\/^givenName:\/\/\")\n\tUSER_LAST_NAME=$(echo \"$USER_DATA\" | grep \"sn:\" | sed \"s\/^sn:\/\/\")\n\tUSER_DISPLAY_NAME=$(echo \"$USER_DATA\" | grep \"displayName:\" | sed \"s\/^displayName:\/\/\")\n\tUSER_NTHASH=$(echo \"$USER_DATA\" | grep \"sambaNTPassword: \" | sed \"s\/sambaNTPassword: \/\/\")\n\n\techo \"Writing $USER_DN\"\n\techo \"dn: CN=$USERUID,CN=Users,DC=example,DC=com\" >> \/root\/users.ldif\n\techo \"changetype: add\" >> \/root\/users.ldif\n\techo \"objectclass: user\" >> \/root\/users.ldif\n\techo \"objectGUID: $USER_GUID\" >> \/root\/users.ldif\n\techo \"sAMAccountName: $USERUID\" >> \/root\/users.ldif\n\techo \"mail:$USER_MAIL\" >> \/root\/users.ldif\n\techo \"displayName:$USER_DISPLAY_NAME\" >> \/root\/users.ldif\n\techo \"sn:$USER_LAST_NAME\" >> \/root\/users.ldif\n\techo \"givenName:$USER_FIRST_NAME\" >> \/root\/users.ldif\n\techo \"\" >> \/root\/users.ldif\n\n\tMEMBERSHIPS=$(echo \"$USER_DATA\" | grep \"memberOf: \" | sed \"s\/memberOf: \/\/\" | sed \"s\/cn=\/\/\" | cut -d ',' -f 1)\n\twhile IFS= read -r MEMBERSHIP; do\n\t\techo \"samba-tool group addmembers '$MEMBERSHIP' $USERUID\" >> \/root\/import.sh\n\tdone &lt;&lt;&lt; \"$MEMBERSHIPS\"\n\techo \"pdbedit -u $USERUID --set-nt-hash $USER_NTHASH\" >> \/root\/import.sh\n        echo \"samba-tool user enable $USERUID\" >> \/root\/import.sh\ndone &lt;&lt;&lt; \"$UIDS\"\n\nEXPORT_GROUPS=$(slapcat -a \"(objectClass=posixGroup)\" | grep \"cn: \" | sed \"s\/cn: \/\/\")\nwhile IFS= read -r GROUPCN; do\n\tif &#91; \"$GROUPCN\" = \"Domain Users\" ] || &#91; \"$GROUPCN\" = \"Domain Admins\" ] || &#91; \"$GROUPCN\" = \"Domain Guests\" ] || &#91; \"$GROUPCN\" = \"Domain Controllers\" ]  || &#91; \"$GROUPCN\" = \"Windows Hosts\" ] || &#91; \"$GROUPCN\" = \"DC Backup Hosts\" ] || &#91; \"$GROUPCN\" = \"DC Slave Hosts\" ] || &#91; \"$GROUPCN\" = \"Computers\" ] || &#91; \"$GROUPCN\" = \"Printer-Admins\" ] || &#91; \"$GROUPCN\" = \"Slave Join\" ] || &#91; \"$GROUPCN\" = \"Backup Join\" ] ; then\n\t\tcontinue\n\tfi\n\tGROUP_DATA=$(slapcat -a \"(cn=$GROUPCN)\")\n\tGROUP_UUID=$(echo \"$GROUP_DATA\" | grep \"entryUUID: \" | sed \"s\/entryUUID: \/\/\")\n\techo \"Writing $GROUPCN\"\n\techo \"dn: CN=$GROUPCN,CN=Users,DC=example,DC=com\" >> \/root\/users.ldif\n\techo \"changetype: add\" >> \/root\/users.ldif\n\techo \"objectClass: top\" >> \/root\/users.ldif\n\techo \"objectClass: group\" >> \/root\/users.ldif\n\techo \"cn: $GROUPCN\" >> \/root\/users.ldif\n\techo \"name: $GROUPCN\" >> \/root\/users.ldif\n\techo \"objectGUID: $GROUP_UUID\" >> \/root\/users.ldif\n\techo \"sAMAccountName: $GROUPCN\" >> \/root\/users.ldif\n\techo \"\" >> \/root\/users.ldif\ndone &lt;&lt;&lt; \"$EXPORT_GROUPS\"\n<\/code><\/pre>\n\n\n\n<p>Now copy the created users.ldif and import.sh files into the \/root directory of your new Samba server. To import the data into Samba, first import the user objects with ldbmodify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ldbmodify -H tdb:\/\/\/var\/lib\/samba\/private\/sam.ldb \/root\/users.ldif --relax<\/code><\/pre>\n\n\n\n<p>Finally set the group memberships and password hashes with executing the import.sh:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>bash \/root\/import.sh<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the past I used the Univention Corporate Server for Identity Management in some organizations. However, I find that UCS is relatively huge and I nowadays I prefer to operate a Samba server in combination with Keycloak, because it is &hellip; <a href=\"https:\/\/sven-seeberg.de\/wp\/?p=1156\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1156","post","type-post","status-publish","format-standard","hentry","category-general"],"_links":{"self":[{"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=\/wp\/v2\/posts\/1156","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1156"}],"version-history":[{"count":15,"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=\/wp\/v2\/posts\/1156\/revisions"}],"predecessor-version":[{"id":1210,"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=\/wp\/v2\/posts\/1156\/revisions\/1210"}],"wp:attachment":[{"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sven-seeberg.de\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}