Make preferred_username optional for Keycloak

This commit adds a new config option 'use-preferred-username' which
can be used with the Keycloak provider to make it optional to use
the preferred_username delivered by Keycloak.

This is useful in situations where the preferred_username is set
as an email address, which don't work as a gerrit username.

Leaving the username unset also allows the user to choose their
own username.

Change-Id: Iff114537527c672190c6a1a41726d2c32bb97810
diff --git a/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java b/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
index 3fbb2ca..c46d088 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
@@ -32,6 +32,7 @@
   static final String FIX_LEGACY_USER_ID = "fix-legacy-user-id";
   static final String DOMAIN = "domain";
   static final String USE_EMAIL_AS_USERNAME = "use-email-as-username";
+  static final String USE_PREFERRED_USERNAME = "use-preferred-username";
   static final String ROOT_URL = "root-url";
   static final String REALM = "realm";
   static final String TENANT = "tenant";
diff --git a/src/main/java/com/googlesource/gerrit/plugins/oauth/KeycloakOAuthService.java b/src/main/java/com/googlesource/gerrit/plugins/oauth/KeycloakOAuthService.java
index 42ff7c4..228dff3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/KeycloakOAuthService.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/KeycloakOAuthService.java
@@ -51,6 +51,7 @@
   private static final String KEYCLOAK_PROVIDER_PREFIX = "keycloak-oauth:";
   private final OAuth20Service service;
   private final String serviceName;
+  private final boolean usePreferredUsername;
 
   @Inject
   KeycloakOAuthService(
@@ -66,6 +67,7 @@
     }
     String realm = cfg.getString(InitOAuth.REALM);
     serviceName = cfg.getString(InitOAuth.SERVICE_NAME, "Keycloak OAuth2");
+    usePreferredUsername = cfg.getBoolean(InitOAuth.USE_PREFERRED_USERNAME, true);
 
     service =
         new ServiceBuilder(cfg.getString(InitOAuth.CLIENT_ID))
@@ -115,12 +117,17 @@
     if (nameElement == null || nameElement.isJsonNull()) {
       throw new IOException("Response doesn't contain name field");
     }
-    String username = usernameElement.getAsString();
+    String usernameAsString = usernameElement.getAsString();
+    String username = null;
+    if (usePreferredUsername) {
+      username = usernameAsString;
+    }
+    String externalId = KEYCLOAK_PROVIDER_PREFIX + usernameAsString;
     String email = emailElement.getAsString();
     String name = nameElement.getAsString();
 
     return new OAuthUserInfo(
-        KEYCLOAK_PROVIDER_PREFIX + username /*externalId*/,
+        externalId /*externalId*/,
         username /*username*/,
         email /*email*/,
         name /*displayName*/,
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 78eb908..91d7288 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -61,6 +61,13 @@
     tenant = "<tenant (optional defaults to organizations if not set)>"
     link-to-existing-office365-accounts = true #Optional, if set will try to link old account with the @PLUGIN@-office365-oauth naming
 
+  [plugin "@PLUGIN@-keycloak-oauth"]
+    root-url = "<root url>" # for example, https://signon.example.com
+    realm = "<realm>"
+    client-id = "<client-id>"
+    client-secret = "<client-secret>"
+    use-preferred-username = true # Optional, if false will not send preferred_username from Keycloak to leave username unset
+
 ```
 
 When one from the sections above is omitted, OAuth SSO is used.
@@ -274,3 +281,14 @@
 This will try to link the old `office365-oauth` external id to the new `azure-oauth` external id automatically.
 Another option is to migrate these manually offline, see [External IDs](https://gerrit-review.googlesource.com/Documentation/config-accounts.html#external-ids)
 for more information.
+
+### Keycloak
+
+When setting up a client in Keycloak for Gerrit, enter a value for the *Client ID* and ensure you choose the `openid-connect`
+protocol and select the `confidential` access type. Once you click save, a *Credentials* tab will appear where you will find
+the Secret.
+
+The root URL will the protocol and hostname of your Keycloak instance (for example, https://signon.example.com).
+
+You can optionally set `use-preferred-username = false` if you would prefer to not have the `preferred_username`
+token be automatically set as the users username, and instead let users choose their own usernames.