blob: cd4437b3b465d773de166d661b2f342973083c23 [file] [log] [blame] [view]
Thomas Draebing16bd87e2021-03-18 10:11:10 +01001---
2title: "Design Doc - Case Insensitive Username Matching - Use Cases"
3permalink: design-docs/case-insensitive-username-matching-use-cases.html
4hide_sidebar: true
5hide_navtoggle: true
6toc: false
7---
8
9# Use Cases
10
11## <a id="definitions"> Definitions
12
13* duplicate usernames/accounts: Usernames or accounts having usernames that are
14 only different in their capitalization.
15 E.g.: `johndoe` and `JohnDoe`. While no true duplicates, they will be referred
16 to as duplicates for readability.
17* external IDs: Gerrit uses (generic) user names in different externalId schemes
18 which are used for different authentication systems.
19
20 Currently the following externalId schemes exist (defined in
21 [ExternalId.java](https://gerrit.googlesource.com/gerrit/+/refs/heads/master/java/com/google/gerrit/server/account/externalids/ExternalId.java#114)):
22
23 * `gerrit` (LDAP)
24 * `username` (authentication REST and git endpoints)
25 * `external` (external authentication e.g. oauth, saml)
26 * `gpgkey` (gpg keys)
27 * `mailto` (email addresses)
28 * `uuid` (randomly created identities constructed by a UUID)
29 * `http` (used by OpenID)
30 * `https` (used by OpenID)
31 * `xri` (used by OpenID)
32
33 The schemes relevant for authentication are: `gerrit`, `username`.
34
35## <a id="primary"> Primary Use Cases
36
37* Gerrit administrators can migrate between LDAP- and SAML identity providers
38 and from LDAP-based accounts to accounts managed by Gerrit, regardless of
39 handling of capitalization of usernames in the different systems.
40
41## <a id="secondary"> Secondary Use Cases
42
43* Prohibit usernames only different in capitalization to make it easier for
44 humans to unequivocally identify users by their username.
45
46## <a id="acceptance-criteria"> Acceptance Criteria
47
48* An administrator should be able to prohibit the creation of accounts with
49 usernames that are only different in capitalization.
50* A tool that allows Gerrit administrators to identify existing duplicate
51 accounts should be available. Already implemented
52 in [change 300308](https://gerrit-review.googlesource.com/c/gerrit/+/300308).
53* The process of dealing with duplicates by either deletion of the external IDs
54 or changing of the username by the administrator should be properly documented
55 and facilitated by Gerrit tools.
56* Gerrit should provide an option to allow clients to be able to login with a
57 username using any capitalization they prefer, i.e. username matching during
58 authentication should be case insensitive. It might be considered to be the
59 default in the future.
60* Display names of accounts using the username as a default display name should
61 use the username as presented during account creation, i.e. with the original
62 capitalization.
63 E.g. if `JohnDoe` is used during account registration this form should appear
64 if mentioned in the UI, regardless of how the username is represented internally.
65* Existing accounts, except for duplicates, should not be disrupted by introducing
66 this change.
67* Gerrit administrators should have a straightforward way of migrating to other
68 identity providers without disrupting users, e.g. from LDAP to SAML or LDAP
69 to Gerrit-serviceuser.
70
71## <a id="background"> Background
72
73Gerrit by default treats usernames case sensitive, i.e. there can be the usernames
74`johndoe` and `JohnDoe` identifying different accounts. There are currently options in
75Gerrit's configuration influencing that aim to achieve case insensitivity
76by storing and matching usernames in all lowercase, regardless of the capitalization
77used by the client. However, these options don't allow to handle accounts with
78mixed- or uppercase usernames created before being set and currently do not
79handle all ways to create accounts in Gerrit. Gerrit provides a tool to convert
80usernames stored in the `gerrit` external ID to all lowercase to solve part of
81the issue. However, this misses accounts created in Gerrit itself, which use the
82`username` external ID. The `username` external ID cannot be converted to all
83lowercase, since this would break the sandbox branches feature, which uses the
84username in the branch name (e.g. `refs/heads/sandbox/${username}/*`).
85
86The existing behavior can lead to issues, when trying to migrate to a different
87identity provider. The scenario encountered by SAP can be taken as an example:
88The identity provider is supposed to be switched from LDAP to SAML. This has to
89happen with minimal disruption for the users, i.e. the username should not change.
90The Gerrit instance has three types of users:
91
92* Internal technical users (created via REST API or the `create-account` SSH command
93 or via the serviceuser-plugin)
94* Technical users managed by LDAP
95* Human users managed by LDAP
96
97Usernames of accounts managed by LDAP are stored in all lowercase
98(`ldap.localUsernameToLowerCase = true`). Other account types are allowed to
99use uppercase letters in the username stored in NoteDB. Some usernames are
100duplicates. The new identity provider does not allow technical users, thus
101technical users managed by LDAP were registered as service users, so that they
102can be used as internal accounts managed by the serviceuser plugin.
103
104The saml-plugin uses the `auth.userNameToLowerCase`-option to convert the username
105used to login to lowercase. This setting blocks all internal technical users
106and service users with uppercase letters in the username, e.g. the service user
107`JenkinsBuild` will not be able to authenticate, since during authentication the
108username is converted to `jenkinsbuild`, which is not present in NoteDB, where
109the external ID `username:JenkinsBuild` is present. This can be fixed by
110adding an option complimentary to `ldap.localUsernameToLowerCase` to the saml-
111plugin. However, with such an option the newly registered service users (former
112LDAP-based technical users) would not able to log in, if the usernames have
113uppercase letters, since this does not match the username in NoteDB that is all
114lowercase.
115
116To illustrate, a list of example scenarios follows:
117
118* LDAP scenario (current state)
119 * `ldap.localUsernameToLowerCase = true`
120 * `auth.userNameToLowerCase = false`
121
122 | user type | username used by user | username in NoteDB | username used in DB lookup | login successful |
123 |----------------------------|-----------------------|--------------------|----------------------------|------------------|
124 | LDAP (human) | johndoe | johndoe | johndoe | true |
125 | LDAP (human) | JohnDoe | johndoe | johndoe | true |
126 | LDAP (technical) | johndoe | johndoe | johndoe | true |
127 | LDAP (technical) | JohnDoe | johndoe | johndoe | true |
128 | internal user/service user | johndoe | johndoe | johndoe | true |
129 | internal user/service user | JohnDoe | JohnDoe | JohnDoe | true |
130
131* SAML scenario 1
132 * technical users (internal users and LDAP-managed technical users) are registered as service users
133 * `auth.userNameToLowerCase = false`
134
135 | user type | username used by user | username in NoteDB | username used in DB lookup | login successful |
136 |----------------------------|-----------------------|--------------------|----------------------------|------------------|
137 | SAML (human) | johndoe | johndoe | johndoe | true |
138 | SAML (human) | JohnDoe | johndoe | JohnDoe | false |
139 | formerly LDAP (technical) | johndoe | johndoe | johndoe | true |
140 | formerly LDAP (technical) | JohnDoe | johndoe | JohnDoe | false |
141 | internal user/service user | johndoe | johndoe | johndoe | true |
142 | internal user/service user | JohnDoe | JohnDoe | JohnDoe | true |
143
144* SAML scenario 2
145 * technical users (internal users and LDAP-managed technical users) are registered as service users
146 * `auth.userNameToLowerCase = true`
147
148 | user type | username used by user | username in NoteDB | username used in DB lookup | login successful |
149 |----------------------------|-----------------------|--------------------|----------------------------|------------------|
150 | SAML (human) | johndoe | johndoe | johndoe | true |
151 | SAML (human) | JohnDoe | johndoe | johndoe | true |
152 | formerly LDAP (technical) | johndoe | johndoe | johndoe | true |
153 | formerly LDAP (technical) | JohnDoe | johndoe | johndoe | true |
154 | internal user/service user | johndoe | johndoe | johndoe | true |
155 | internal user/service user | JohnDoe | JohnDoe | johndoe | false |
156
157* SAML scenario 3
158 * technical users (internal users and LDAP-managed technical users) are registered as service users
159 * `auth.userNameToLowerCase = true`
160 * `saml.localUsernameToLowerCase = true` (not yet implemented)
161
162 | user type | username used by user | username in NoteDB | username used in DB lookup | login successful |
163 |----------------------------|-----------------------|--------------------|----------------------------|------------------|
164 | SAML (human) | johndoe | johndoe | johndoe | true |
165 | SAML (human) | JohnDoe | johndoe | johndoe | true |
166 | formerly LDAP (technical) | johndoe | johndoe | johndoe | true |
167 | formerly LDAP (technical) | JohnDoe | johndoe | johndoe | true |
168 | internal user/service user | johndoe | johndoe | johndoe | true |
169 | internal user/service user | JohnDoe | JohnDoe | johndoe | false |
170
171* SAML scenario 4
172 * technical users (internal users and LDAP-managed technical users) are registered as service users
173 * `auth.userNameToLowerCase = false`
174 * `saml.localUsernameToLowerCase = true` (not yet implemented)
175
176 | user type | username used by user | username in NoteDB | username used in DB lookup | login successful |
177 |----------------------------|-----------------------|--------------------|----------------------------|------------------|
178 | SAML (human) | johndoe | johndoe | johndoe | true |
179 | SAML (human) | JohnDoe | johndoe | johndoe | true |
180 | formerly LDAP (technical) | johndoe | johndoe | johndoe | true |
181 | formerly LDAP (technical) | JohnDoe | johndoe | JohnDoe | false |
182 | internal user/service user | johndoe | johndoe | johndoe | true |
183 | internal user/service user | JohnDoe | JohnDoe | johndoe | true |
184
185
186While this example uses non-core plugins and is very specific, it shows that
187having different accounts with usernames only different in capitalization can
188lead to hard to resolve issues or disruption of users. Further, there is likely
189no good use case to support case sensitive usernames. Usernames only different
190in capitalization might rather lead to confusion in identifying a user. Thus,
191account data could be made easier to manage by matching accounts case insensitive
192during authentication.