1 of 21

Case-insensitive usernames in Gerrit

Matthias Sohn (SAP)

2 of 21

We used

  • LDAP authentication for
    • Many thousand human users
    • Few hundred technical users

3 of 21

We used

  • LDAP authentication for
    • Many thousand human users
    • Few hundred technical users
  • Our LDAP is case-insensitive and we used

4 of 21

We used

  • LDAP authentication for
    • Many thousand human users
    • Few hundred technical users
  • Our LDAP is case-insensitive and we used
  • LDAP usernames in external-ids were �case-insensitive/not case-preserving
  • Other usernames were case-sensitive

5 of 21

We used

  • Hundreds of service users via serviceuser plugin
    • self-service for end users
    • usernames stored case-sensitive in external-ids
    • service users are stored in serviceuser.db in git config format
    • git config section/subsection names are case-insensitive/case-preserving
  • Some old-style internal technical users
    • usernames stored case-sensitive in external-ids

6 of 21

Migrate to SAP ID Service

  • Motivation
    • 2 factor authentication
    • SAML authentication
    • Also available in public cloud
    • Better availability�
  • Replicates from corporate LDAP
    • internal users, groups�
  • No support for technical users

7 of 21

How to limit migration effort for users ?

  • Use serviceuser plugin for all technical users
  • Migrate technical LDAP users to become internal service users

8 of 21

How to limit migration effort for users ?

  • Use serviceuser plugin for all technical users
  • Migrate technical LDAP users to become internal service users
  • New command to register technical LDAP user as a service user�$ ssh -p 29418 gerrit.host serviceuser register� --owner jd_owners JohnDoe
    • Adds entry in serviceuser.db on refs/meta/config branch of All-Projects

9 of 21

How to limit migration effort for users ?

  • Use serviceuser plugin for all technical users
  • Migrate technical LDAP users to become internal service users
  • New command to register technical LDAP user as a service user�$ ssh -p 29418 gerrit.host serviceuser register� --owner jd_owners JohnDoe
    • Adds entry in serviceuser.db on refs/meta/config branch of All-Projects
  • After migration such users continue to exist as service users
  • Owners can maintain service users via serviceuser plugin's self-service UI

10 of 21

Problem

Different behavior regarding case of usernames in external-ids�due to the configuration we used before:

username of

  • LDAP users were case-insensitive/not case-preserving
  • old-style internal users and service users were case-sensitive
  • service users are stored case-insensitive/case-preserving in serviceuser.db (due to git config format)

11 of 21

Example - technical user 'BuildBot'

  • Register 'BuildBot' as service user
  • With LDAP authentication:

760a1054f05d5fe7a6110256d88e95fb71c700a0 'username:buildbot'

serviceuser.db:

[user "BuildBot"]

creatorId = 1000000

createdBy = admin

createdAt = 10 Feb 2021 00:13:35

12 of 21

Example - technical user 'BuildBot'

  • Register 'BuildBot' as service user
  • With LDAP authentication:

760a1054f05d5fe7a6110256d88e95fb71c700a0 'username:buildbot'

  • With SAP IDP authentication
    • technical users authenticated as service users
    • service user is case-sensitive
    • client still tries to authenticate as 'BuildBot'

c1dec325e27ad0f815b7d105b352d6187cd948b9 'username:BuildBot'

serviceuser.db:

[user "BuildBot"]

creatorId = 1000000

createdBy = admin

createdAt = 10 Feb 2021 00:13:35

13 of 21

Example - technical user 'BuildBot'

  • Register 'BuildBot' as service user
  • With LDAP authentication:

760a1054f05d5fe7a6110256d88e95fb71c700a0 'username:buildbot'

  • With SAP IDP authentication
    • technical users authenticated as service users
    • service user is case-sensitive
    • client still tries to authenticate as 'BuildBot'

c1dec325e27ad0f815b7d105b352d6187cd948b9 'username:BuildBot'

Lookup of external-id fails ! �This spoiled the plan for a smooth migration.

serviceuser.db:

[user "BuildBot"]

creatorId = 1000000

createdBy = admin

createdAt = 10 Feb 2021 00:13:35

14 of 21

Example - technical user 'BuildBot'

  • Register 'BuildBot' as service user
  • With LDAP authentication:

760a1054f05d5fe7a6110256d88e95fb71c700a0 'username:buildbot'

  • With SAP IDP authentication
    • technical users authenticated as service users
    • service user is case-sensitive
    • client still tries to authenticate as 'BuildBot'

c1dec325e27ad0f815b7d105b352d6187cd948b9 'username:BuildBot'

Lookup of external-id fails ! �This spoiled the plan for a smooth migration.

→ Fix this by always computing � id = sha1(toLowerCase(external-id)) to make lookup case-insensitive (thanks Edwin for the idea)

serviceuser.db:

[user "BuildBot"]

creatorId = 1000000

createdBy = admin

createdAt = 10 Feb 2021 00:13:35

15 of 21

Solution

New option auth.userNameCaseInsensitive set to true:

  • Store usernames case-preserving in external-ids
  • Compute id of external-ids case-insensitive (converted to lower-case) for scheme gerrit: and username:
    • lookup via id becomes case-insensitive�
  • Duplicate usernames only differing in case need to be cleaned up:
    • delete all external-ids to cleanup an account: 'username:johndoe' and 'username:JohnDoe'
  • Offline migration tool to recompute id of external-ids

16 of 21

Example - username 'JohnDoe'

case-sensitive :

id = shasum(external-id)

90194fbd033d9a544d9e7df2ccbfdfa2d2e78061 'username:JohnDoe'ee8942eac80eb867f16d4d7b25c8b6999e221d71 'username:johndoe'�166110abb028006a2bb523cceff5cdc0ba6cbe06 'username:JOHNDOE'

17 of 21

Example - username 'JohnDoe'

case-sensitive :

id = shasum(external-id)

90194fbd033d9a544d9e7df2ccbfdfa2d2e78061 'username:JohnDoe'ee8942eac80eb867f16d4d7b25c8b6999e221d71 'username:johndoe'�166110abb028006a2bb523cceff5cdc0ba6cbe06 'username:JOHNDOE'

case-insensitive/case-preserving:

id = shasum(toLower(external-id))

ee8942eac80eb867f16d4d7b25c8b6999e221d71 'username:JohnDoe'ee8942eac80eb867f16d4d7b25c8b6999e221d71 'username:johndoe'�ee8942eac80eb867f16d4d7b25c8b6999e221d71 'username:JOHNDOE'

18 of 21

Experience

  • Migration went smooth and was quick
    • a test migration of 280k users of Eclipse site took 10min�
  • Only few technical users use http and needed to generate new http password
  • Phased roll-out, switched to new auth for a couple of test days to identify issues and limit risk
  • We use this in production on 2.16 and 3.2 (internal fork)�
  • case-insensitive/case-preserving usernames seem more intuitive and cause less issues

19 of 21

Status in open source project

Internally

  • Developed on stable-3.2
  • Downported to 2.16

Upstream

  • Ported to stable-3.4
  • Didn't make it for 3.4
  • Hence moved to master to be included in 3.5

20 of 21

Open question

Does anybody need case-sensitive usernames ?

Option 1: Optional feature via new option auth.userNameCaseInsensitive

  • Pro: already implemented, case-sensitive still possible
  • Cons: requires migration, one option more, more code to maintain

Option 2: Next release of Gerrit handles usernames always case-insensitive

  • Migration during upgrade
  • Pro: less options, less code to maintain
  • Cons: can't use case-sensitive anymore, forced to cleanup duplicate usernames only differing in case

21 of 21

Kudos to

  • Thomas Dräbing for all the heavy lifting
  • DavidO, Edwin, Han-Wen, Luca, Marija, Patrick for reviewing

Design Doc: case-insensitive usernames

Changes: #case-insensitive-usernames