diff --git a/CloudronManifest.json b/CloudronManifest.json index 0f96bd5..f775300 100644 --- a/CloudronManifest.json +++ b/CloudronManifest.json @@ -16,6 +16,7 @@ "postgresql": {}, "redis": {}, "sendmail": {}, + "ldap": {}, "oidc": { "loginRedirectUri": "/auth/auth/openid_connect/callback" }, "scheduler": { "cleanup": { diff --git a/Dockerfile b/Dockerfile index 72d9d7b..efda3ca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -69,7 +69,9 @@ RUN ln -sf /run/mastodon/supervisord.log /var/log/supervisor/supervisord.log RUN ln -fs /app/data/env.production /app/code/.env.production RUN ln -fs /app/data/system /app/code/public/system -COPY start.sh cleanup.sh config.sh env.template cache-env.sh.template /app/pkg/ +COPY migrateUsers.js start.sh cleanup.sh config.sh env.template cache-env.sh.template /app/pkg/ + +RUN chmod +x /app/pkg/migrateUsers.js CMD [ "/app/pkg/start.sh" ] diff --git a/migrateUsers.js b/migrateUsers.js new file mode 100755 index 0000000..638cdae --- /dev/null +++ b/migrateUsers.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node + +'use strict'; + +const execSync = require('child_process').execSync; + +const ldapUserSearchCmd = `ldapsearch -LLL -x -H "${process.env.CLOUDRON_LDAP_URL}" -D "${process.env.CLOUDRON_LDAP_BIND_DN}" -w "${process.env.CLOUDRON_LDAP_BIND_PASSWORD}" -b "${process.env.CLOUDRON_LDAP_USERS_BASE_DN}"` +const postgresCmd = `PGPASSWORD=${process.env.CLOUDRON_POSTGRESQL_PASSWORD} psql -h ${process.env.CLOUDRON_POSTGRESQL_HOST} -p ${process.env.CLOUDRON_POSTGRESQL_PORT} -U ${process.env.CLOUDRON_POSTGRESQL_USERNAME} -d ${process.env.CLOUDRON_POSTGRESQL_DATABASE}` + +let usersTableExists = execSync(`${postgresCmd} -AXqtc "SELECT count(*) FROM information_schema.tables WHERE table_schema LIKE 'public' AND table_type LIKE 'BASE TABLE' AND table_name = 'users'"`); +if (usersTableExists == 0) { + console.log("DB hasn't been initialised yet. Nothing to migrate."); + process.exit(0); +} + +let ldapProfiles = execSync(`${postgresCmd} -AXqtc "SELECT count(*) FROM users u JOIN accounts a ON a.id=u.account_id LEFT JOIN identities i ON i.uid=a.username WHERE i.uid IS NULL"`); +console.log(`LDAP profiles in DB: ${ldapProfiles}`); +if (ldapProfiles == 0) { + console.log("Nothing to migrate. All users' profiles are up-to-date."); + process.exit(0); +} + +const ldapSearchOutput = execSync(ldapUserSearchCmd, { encoding: 'utf8' }); + +const users = {}; + +let userId; +for (let line of ldapSearchOutput.split('\n')) { + if (line.startsWith('mail:')) userId = line.split(':')[1].trim(); + if (line.startsWith('username:')) users[userId] = line.split(':')[1].trim(); +} + +console.log('Found usermapping:', users); + +for (let email in users) { + let uid = execSync(`${postgresCmd} -AXqtc "SELECT id FROM users WHERE email='${email}'"`).toString().trim(); + if (!uid) + continue; + + console.log(`Migrate ${email}/${users[email]} to OIDC`); + execSync(`${postgresCmd} -c "INSERT INTO identities (provider, uid, user_id, created_at, updated_at) VALUES ('openid_connect', '${users[email]}', ${uid}, NOW(), NOW())"`); + console.log(`"INSERT INTO identities (provider, uid, user_id, created_at, updated_at) VALUES ('openid_connect', '${users[email]}', ${uid}, NOW(), NOW())"`); +} + +console.log('Done'); diff --git a/start.sh b/start.sh index fd9a9e2..cc3900b 100755 --- a/start.sh +++ b/start.sh @@ -30,7 +30,7 @@ sed -e "s/DB_HOST=.*/DB_HOST=${CLOUDRON_POSTGRESQL_HOST}/g" \ -e "s/WEB_DOMAIN=.*/WEB_DOMAIN=${CLOUDRON_APP_DOMAIN}/g" \ -i /app/data/env.production -# migrate LDAP settings to OIDC +# migrate LDAP settings to OIDC (should be removed on the next release) if grep -q "^LDAP_ENABLED" /app/data/env.production; then # get rid LDAP settings sed -e "s/LDAP_.*//g" \ @@ -48,11 +48,15 @@ OIDC_REDIRECT_URI= OIDC_DISCOVERY= OIDC_SCOPE= OIDC_UID_FIELD= +OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED= EOT - fi if [[ -n "${CLOUDRON_OIDC_ISSUER:-}" ]]; then + # should be removed on the next release + echo "==> migrating LDAP users to OIDC" + /app/pkg/migrateUsers.js + echo "==> Setting up OIDC" sed -e "s/OIDC_ENABLED=.*/OIDC_ENABLED=true/g" \ -e "s/OIDC_DISPLAY_NAME=.*/OIDC_DISPLAY_NAME=Cloudron/g" \ @@ -63,6 +67,7 @@ if [[ -n "${CLOUDRON_OIDC_ISSUER:-}" ]]; then -e "s/OIDC_DISCOVERY=.*/OIDC_DISCOVERY=true/g" \ -e "s/OIDC_SCOPE=.*/OIDC_SCOPE=openid,profile,email/g" \ -e "s/OIDC_UID_FIELD=.*/OIDC_UID_FIELD=sub/g" \ + -e "s/OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED=.*/OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true/g" \ -i /app/data/env.production fi