Migration from LDAP to OIDC: Forgejo
enIn my hackerspace we operate various services for our members. Up until this month, most of these services used to do user authentication against a LDAP server. For a multitude of reasons, we replaced the LDAP server with an OpenID Connect SSO using a Keycloak server as the OIDC Identity Provider.
In this series of articles I summarize the efforts required to migrate each of the services from LDAP to OIDC authentication. This article covers the setup and migration in Forgejo.
OIDC Setup in Forgejo
Forgejo is a fork of the Gitea Git hosting platform that has emerged recently as a result of the takeover of the Gitea project by for-profit Gitea Ltd. Since both projects are still mostly identical at the time of writing, this section should apply 1:1 to Gitea as well.
To get started, sign into Forgejo as an admin user and create a new authentication source in the settings:
- Choose
OAuth2
as the authentication type andOpenID Connect
as OAuth2 provider. - Fill in the Client ID and Client Secret as well as the auto-discovery URL.
- Use at least
openid profile email
as the scope, and expand as necessary.
Once the authentication source is created and enabled, users can start signing in via OIDC. If a user has already signed in before using their LDAP password, they will be prompted for said password in order to "link" their OIDC user to the existing LDAP user. Whether users actually do this or not does not affect the migration.
Migration of Users From LDAP to OIDC
To understand the next migration steps, we first need to get an overview of the different types of names used to identify users in Forgejo:
- The username is the name users are known as within Forgejo. You can consider this name to be a primary key (though not exactly true at the database schema level).
- The display name is the name shown in the web UI.
- The authentication sign-in name is the name provided by the authentication source.
This decoupling of the username and authentication name simplifies the
migration a lot. With an LDAP authentication source, the
authentication name is configurable - usually you'd choose an LDAP
attribute such as uid
or sAMAccoutName
or (if you are really
concerned about all-time uniqueness) objectGUID
.
For the OIDC authentication source, the authentication name is not
configurable - Forgejo insists on using the OIDC Subject Identifier
(the sub
key in the id_token
). Keycloak generates an UUID for the
subject identifier. Fortunately, Forgejo is smart enough to also
consider the preferred_username
token claim, and maps it to the
Forgejo username - and prompts an already existing user for linking
the account, as mentioned above.
However, since we wanted to disable LDAP authentication, this account linking would not have worked, so we needed to change the mapping for all users. For this, you need to obtain the subject ids and usernames of all users in Keycloak - this is most easily done by asking Keycloak's database (using PostgreSQL in this case):
$ sudo -u postgres psql keycloak
keycloak=# SELECT id, username FROM user_entity;
id | username
--------------------------------------+----------
7ac0e93b-8725-4efa-95dc-0e20c6dbfa0a | s3lph
8933480e-146f-4e7c-ac9c-9c8adfd69069 | s4lph
d398d274-7d9a-45b3-96e7-96b8811afa72 | s5lph
If there's only a small number of users in your Forgejo instance, you could now edit every single one in the admin settings, and change its authentication source to the OIDC provider and the login name to this subject identifier. The more scalable approach, however, would be to transform this list into a series of UPDATE statements for Forgejo's database (in our case, MariaDB is used here):
BEGIN;
UPDATE user SET login_name = '7ac0e93b-8725-4efa-95dc-0e20c6dbfa0a', login_type = 6, login_source = 4 where lower_name = 's3lph';
UPDATE user SET login_name = '8933480e-146f-4e7c-ac9c-9c8adfd69069', login_type = 6, login_source = 4 where lower_name = 's4lph';
UPDATE user SET login_name = 'd398d274-7d9a-45b3-96e7-96b8811afa72', login_type = 6, login_source = 4 where lower_name = 's5lph';
COMMIT;
Note the additional columns login_type
and login_source
we need to modify:
login_type
is the type of login source being used. This is6
for all OAuth sources. The list of type identifiers can be found in the Forgejo source code.login_source
is the numeric id of the OIDC login source you created in Forgejo. You can see this ID in the list of authentication sources in the Forgejo admin settings.
Finally, if you configured Forgejo to import SSH public keys from LDAP, you need to remove the mapping from SSH keys to the login source they came from. Otherwise, users with such keys won't be able to open their SSH key settings anymore:
UPDATE public_key SET login_source_id = 0 WHERE login_source_id = 1;
Replace the login source ID in the WHERE
clause with the ID of your
LDAP authentiation source (again, to be found in the Forgejo admin
settings).
This concludes the OIDC migration of Forgejo, and the LDAP authentication source can now be safely disabled or removed.
Tips and Tricks
If user self-registration is disabled on your Forgejo
instance, you should add the following to your app.ini
so that new
OIDC users can sign into Forgejo without admin intervention:
[oauth2_client]
ENABLE_AUTO_REGISTRATION=true
Forgejo does not automatically redirect to the IdP for login - users always have to click the "Login with OpenID" button. If you want your users to be redirected to the SSO automatically when they try to log in, you have to configure this in your reverse proxy. For example, in Apache 2:
RewriteEngine on
RewriteCond %{QUERY_STRING} !local=1
RewriteCond %{REQUEST_METHOD} GET
RewriteRule ^/user/login$ /user/oauth2/oidc [L,R,QSD]
Replace the last URL component (/oidc
) with the name you gave to
your OIDC authentication source in Forgejo. The RewriteCond
s in
this config allow you to append ?local=1
to disable the redirect,
e.g. if you need to sign in as a local admin user.