Design Doc: Case Insensitive Username Matching

Change-Id: Iac0341d0ccd975166f68d3a8a933e1aadc01243e
diff --git a/pages/design-docs/case-insensitive-username-matching/index.md b/pages/design-docs/case-insensitive-username-matching/index.md
new file mode 100644
index 0000000..796bcff
--- /dev/null
+++ b/pages/design-docs/case-insensitive-username-matching/index.md
@@ -0,0 +1,13 @@
+---
+title: ""
+permalink: design-docs/case-insensitive-username-matching.html
+hide_sidebar: true
+hide_navtoggle: true
+toc: false
+---
+
+# Design Doc - Case Insensitive Username Matching
+
+* [Use Cases](/design-docs/case-insensitive-username-matching-use-cases.html)
+<!-- * [Solution - Threaded Feedback](/design-docs/case-insensitive-username-matching-solution.html) -->
+<!-- * [Conclusion](/design-docs/case-insensitive-username-matching-conclusion.html) -->
diff --git a/pages/design-docs/case-insensitive-username-matching/use-cases.md b/pages/design-docs/case-insensitive-username-matching/use-cases.md
new file mode 100644
index 0000000..cd4437b
--- /dev/null
+++ b/pages/design-docs/case-insensitive-username-matching/use-cases.md
@@ -0,0 +1,192 @@
+---
+title: "Design Doc - Case Insensitive Username Matching - Use Cases"
+permalink: design-docs/case-insensitive-username-matching-use-cases.html
+hide_sidebar: true
+hide_navtoggle: true
+toc: false
+---
+
+# Use Cases
+
+## <a id="definitions"> Definitions
+
+* duplicate usernames/accounts: Usernames or accounts having usernames that are
+  only different in their capitalization.
+  E.g.: `johndoe` and `JohnDoe`. While no true duplicates, they will be referred
+  to as duplicates for readability.
+* external IDs: Gerrit uses (generic) user names in different externalId schemes
+  which are used for different authentication systems.
+
+  Currently the following externalId schemes exist (defined in
+  [ExternalId.java](https://gerrit.googlesource.com/gerrit/+/refs/heads/master/java/com/google/gerrit/server/account/externalids/ExternalId.java#114)):
+
+  * `gerrit`   (LDAP)
+  * `username` (authentication REST and git endpoints)
+  * `external` (external authentication e.g. oauth, saml)
+  * `gpgkey`   (gpg keys)
+  * `mailto`   (email addresses)
+  * `uuid`     (randomly created identities constructed by a UUID)
+  * `http`     (used by OpenID)
+  * `https`    (used by OpenID)
+  * `xri`      (used by OpenID)
+
+  The schemes relevant for authentication are: `gerrit`, `username`.
+
+## <a id="primary"> Primary Use Cases
+
+* Gerrit administrators can migrate between LDAP- and SAML identity providers
+  and from LDAP-based accounts to accounts managed by Gerrit, regardless of
+  handling of capitalization of usernames in the different systems.
+
+## <a id="secondary"> Secondary Use Cases
+
+* Prohibit usernames only different in capitalization to make it easier for
+  humans to unequivocally identify users by their username.
+
+## <a id="acceptance-criteria"> Acceptance Criteria
+
+* An administrator should be able to prohibit the creation of accounts with
+  usernames that are only different in capitalization.
+* A tool that allows Gerrit administrators to identify existing duplicate
+  accounts should be available. Already implemented
+  in [change 300308](https://gerrit-review.googlesource.com/c/gerrit/+/300308).
+* The process of dealing with duplicates by either deletion of the external IDs
+  or changing of the username by the administrator should be properly documented
+  and facilitated by Gerrit tools.
+* Gerrit should provide an option to allow clients to be able to login with a
+  username using any capitalization they prefer, i.e. username matching during
+  authentication should be case insensitive. It might be considered to be the
+  default in the future.
+* Display names of accounts using the username as a default display name should
+  use the username as presented during account creation, i.e. with the original
+  capitalization.
+  E.g. if `JohnDoe` is used during account registration this form should appear
+  if mentioned in the UI, regardless of how the username is represented internally.
+* Existing accounts, except for duplicates, should not be disrupted by introducing
+  this change.
+* Gerrit administrators should have a straightforward way of migrating to other
+  identity providers without disrupting users, e.g. from LDAP to SAML or LDAP
+  to Gerrit-serviceuser.
+
+## <a id="background"> Background
+
+Gerrit by default treats usernames case sensitive, i.e. there can be the usernames
+`johndoe` and `JohnDoe` identifying different accounts. There are currently options in
+Gerrit's configuration influencing that aim to achieve case insensitivity
+by storing and matching usernames in all lowercase, regardless of the capitalization
+used by the client. However, these options don't allow to handle accounts with
+mixed- or uppercase usernames created before being set and currently do not
+handle all ways to create accounts in Gerrit. Gerrit provides a tool to convert
+usernames stored in the `gerrit` external ID to all lowercase to solve part of
+the issue. However, this misses accounts created in Gerrit itself, which use the
+`username` external ID. The `username` external ID cannot be converted to all
+lowercase, since this would break the sandbox branches feature, which uses the
+username in the branch name (e.g. `refs/heads/sandbox/${username}/*`).
+
+The existing behavior can lead to issues, when trying to migrate to a different
+identity provider. The scenario encountered by SAP can be taken as an example:
+The identity provider is supposed to be switched from LDAP to SAML. This has to
+happen with minimal disruption for the users, i.e. the username should not change.
+The Gerrit instance has three types of users:
+
+* Internal technical users (created via REST API or the `create-account` SSH command
+  or via the serviceuser-plugin)
+* Technical users managed by LDAP
+* Human users managed by LDAP
+
+Usernames of accounts managed by LDAP are stored in all lowercase
+(`ldap.localUsernameToLowerCase = true`). Other account types are allowed to
+use uppercase letters in the username stored in NoteDB. Some usernames are
+duplicates. The new identity provider does not allow technical users, thus
+technical users managed by LDAP were registered as service users, so that they
+can be used as internal accounts managed by the serviceuser plugin.
+
+The saml-plugin uses the `auth.userNameToLowerCase`-option to convert the username
+used to login to lowercase. This setting blocks all internal technical users
+and service users with uppercase letters in the username, e.g. the service user
+`JenkinsBuild` will not be able to authenticate, since during authentication the
+username is converted to `jenkinsbuild`, which is not present in NoteDB, where
+the external ID `username:JenkinsBuild` is present. This can be fixed by
+adding an option complimentary to `ldap.localUsernameToLowerCase` to the saml-
+plugin. However, with such an option the newly registered service users (former
+LDAP-based technical users) would not able to log in, if the usernames have
+uppercase letters, since this does not match the username in NoteDB that is all
+lowercase.
+
+To illustrate, a list of example scenarios follows:
+
+* LDAP scenario (current state)
+  * `ldap.localUsernameToLowerCase = true`
+  * `auth.userNameToLowerCase = false`
+
+  | user type                  | username used by user | username in NoteDB | username used in DB lookup | login successful |
+  |----------------------------|-----------------------|--------------------|----------------------------|------------------|
+  | LDAP (human)               | johndoe               | johndoe            | johndoe                    | true             |
+  | LDAP (human)               | JohnDoe               | johndoe            | johndoe                    | true             |
+  | LDAP (technical)           | johndoe               | johndoe            | johndoe                    | true             |
+  | LDAP (technical)           | JohnDoe               | johndoe            | johndoe                    | true             |
+  | internal user/service user | johndoe               | johndoe            | johndoe                    | true             |
+  | internal user/service user | JohnDoe               | JohnDoe            | JohnDoe                    | true             |
+
+* SAML scenario 1
+  * technical users (internal users and LDAP-managed technical users) are registered as service users
+  * `auth.userNameToLowerCase = false`
+
+  | user type                  | username used by user | username in NoteDB | username used in DB lookup | login successful |
+  |----------------------------|-----------------------|--------------------|----------------------------|------------------|
+  | SAML (human)               | johndoe               | johndoe            | johndoe                    | true             |
+  | SAML (human)               | JohnDoe               | johndoe            | JohnDoe                    | false            |
+  | formerly LDAP (technical)  | johndoe               | johndoe            | johndoe                    | true             |
+  | formerly LDAP (technical)  | JohnDoe               | johndoe            | JohnDoe                    | false            |
+  | internal user/service user | johndoe               | johndoe            | johndoe                    | true             |
+  | internal user/service user | JohnDoe               | JohnDoe            | JohnDoe                    | true             |
+
+* SAML scenario 2
+  * technical users (internal users and LDAP-managed technical users) are registered as service users
+  * `auth.userNameToLowerCase = true`
+
+  | user type                  | username used by user | username in NoteDB | username used in DB lookup | login successful |
+  |----------------------------|-----------------------|--------------------|----------------------------|------------------|
+  | SAML (human)               | johndoe               | johndoe            | johndoe                    | true             |
+  | SAML (human)               | JohnDoe               | johndoe            | johndoe                    | true             |
+  | formerly LDAP (technical)  | johndoe               | johndoe            | johndoe                    | true             |
+  | formerly LDAP (technical)  | JohnDoe               | johndoe            | johndoe                    | true             |
+  | internal user/service user | johndoe               | johndoe            | johndoe                    | true             |
+  | internal user/service user | JohnDoe               | JohnDoe            | johndoe                    | false            |
+
+* SAML scenario 3
+  * technical users (internal users and LDAP-managed technical users) are registered as service users
+  * `auth.userNameToLowerCase = true`
+  * `saml.localUsernameToLowerCase = true` (not yet implemented)
+
+  | user type                  | username used by user | username in NoteDB | username used in DB lookup | login successful |
+  |----------------------------|-----------------------|--------------------|----------------------------|------------------|
+  | SAML (human)               | johndoe               | johndoe            | johndoe                    | true             |
+  | SAML (human)               | JohnDoe               | johndoe            | johndoe                    | true             |
+  | formerly LDAP (technical)  | johndoe               | johndoe            | johndoe                    | true             |
+  | formerly LDAP (technical)  | JohnDoe               | johndoe            | johndoe                    | true             |
+  | internal user/service user | johndoe               | johndoe            | johndoe                    | true             |
+  | internal user/service user | JohnDoe               | JohnDoe            | johndoe                    | false            |
+
+* SAML scenario 4
+  * technical users (internal users and LDAP-managed technical users) are registered as service users
+  * `auth.userNameToLowerCase = false`
+  * `saml.localUsernameToLowerCase = true` (not yet implemented)
+
+  | user type                  | username used by user | username in NoteDB | username used in DB lookup | login successful |
+  |----------------------------|-----------------------|--------------------|----------------------------|------------------|
+  | SAML (human)               | johndoe               | johndoe            | johndoe                    | true             |
+  | SAML (human)               | JohnDoe               | johndoe            | johndoe                    | true             |
+  | formerly LDAP (technical)  | johndoe               | johndoe            | johndoe                    | true             |
+  | formerly LDAP (technical)  | JohnDoe               | johndoe            | JohnDoe                    | false            |
+  | internal user/service user | johndoe               | johndoe            | johndoe                    | true             |
+  | internal user/service user | JohnDoe               | JohnDoe            | johndoe                    | true             |
+
+
+While this example uses non-core plugins and is very specific, it shows that
+having different accounts with usernames only different in capitalization can
+lead to hard to resolve issues or disruption of users. Further, there is likely
+no good use case to support case sensitive usernames. Usernames only different
+in capitalization might rather lead to confusion in identifying a user. Thus,
+account data could be made easier to manage by matching accounts case insensitive
+during authentication.
diff --git a/pages/design-docs/index.md b/pages/design-docs/index.md
index 331e630..7aa81bc 100644
--- a/pages/design-docs/index.md
+++ b/pages/design-docs/index.md
@@ -27,6 +27,7 @@
 - [Instance Id](design-docs/instance-id.html) by Fabio Ponciroli, approved 2020-05-05
 - [Checks UI - CI Reboot](design-docs/ci-reboot.html) by Ben Rohlfs, approved 2020-08-20
 - [Deletion of Groups](design-docs/delete-groups.html) by Gal Paikin / Jacek Centkowski, approved as plugin 2020-09-01
+- [Case Insensitive Username Matching](design-docs/case-insensitive-username-matching.html) by Thomas Draebing, proposed 2021-03-18
 
 ## Reviews of Design Documents