[SAP IAS] Add optional support for PKCE

Change-Id: I3fcaedd58266fb7bf7aeef5274e14e16c8cffe25
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 442a52a..4458431 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
@@ -46,6 +46,7 @@
   static final String PLUGIN_SECTION = "plugin";
   public static final String CLIENT_ID = "client-id";
   public static final String CLIENT_SECRET = "client-secret";
+  public static final String ENABLE_PKCE = "enable-pkce";
   public static final String LINK_TO_EXISTING_OPENID_ACCOUNT = "link-to-existing-openid-accounts";
   public static final String FIX_LEGACY_USER_ID = "fix-legacy-user-id";
   public static final String DOMAIN = "domain";
@@ -167,6 +168,8 @@
             isConfigured(iasOAuthProviderSection), "Use SAP IAS OAuth provider for Gerrit login ?");
     if (configureIASOAuthProvider && configureOAuth(iasOAuthProviderSection)) {
       checkRootUrl(iasOAuthProviderSection.string("SAP IAS Root URL", ROOT_URL, null));
+      iasOAuthProviderSection.string(
+          "Enable PKCE for SAP IAS OAuth provider?", ENABLE_PKCE, "false");
     }
 
     boolean configureLemonLDAPOAuthProvider =
diff --git a/src/main/java/com/googlesource/gerrit/plugins/oauth/sap/SAPIasOAuthService.java b/src/main/java/com/googlesource/gerrit/plugins/oauth/sap/SAPIasOAuthService.java
index adac216..78a3739 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/sap/SAPIasOAuthService.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/sap/SAPIasOAuthService.java
@@ -18,6 +18,8 @@
 
 import com.github.scribejava.core.builder.ServiceBuilder;
 import com.github.scribejava.core.model.OAuth2AccessToken;
+import com.github.scribejava.core.oauth.AccessTokenRequestParams;
+import com.github.scribejava.core.oauth.AuthorizationUrlBuilder;
 import com.github.scribejava.core.oauth.OAuth20Service;
 import com.google.common.base.Strings;
 import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
@@ -52,6 +54,8 @@
   private final String serviceName;
   private final String rootUrl;
   private final boolean linkExistingGerrit;
+  private final boolean enablePKCE;
+  private final AuthorizationUrlBuilder authorizationUrlBuilder;
   private final String extIdScheme;
 
   @Inject
@@ -65,12 +69,14 @@
     }
     serviceName = cfg.getString(InitOAuth.SERVICE_NAME, "SAP IAS");
     linkExistingGerrit = cfg.getBoolean(InitOAuth.LINK_TO_EXISTING_GERRIT_ACCOUNT, false);
+    enablePKCE = cfg.getBoolean(InitOAuth.ENABLE_PKCE, false);
     service =
         new ServiceBuilder(cfg.getString(InitOAuth.CLIENT_ID))
             .apiSecret(cfg.getString(InitOAuth.CLIENT_SECRET))
             .callback(canonicalWebUrl + "oauth")
             .defaultScope("openid profile email")
             .build(new SAPIasApi(rootUrl));
+    authorizationUrlBuilder = service.createAuthorizationUrlBuilder();
     extIdScheme = OAuthServiceProviderExternalIdScheme.create(PROVIDER_NAME);
   }
 
@@ -99,7 +105,11 @@
   @Override
   public OAuthToken getAccessToken(OAuthVerifier rv) {
     try {
-      OAuth2AccessToken accessToken = service.getAccessToken(rv.getValue());
+      AccessTokenRequestParams reqParams = AccessTokenRequestParams.create(rv.getValue());
+      if (enablePKCE) {
+        reqParams.pkceCodeVerifier(authorizationUrlBuilder.getPkce().getCodeVerifier());
+      }
+      OAuth2AccessToken accessToken = service.getAccessToken(reqParams);
       return new OAuthToken(
           accessToken.getAccessToken(), accessToken.getTokenType(), accessToken.getRawResponse());
     } catch (InterruptedException | ExecutionException | IOException e) {
@@ -111,7 +121,10 @@
 
   @Override
   public String getAuthorizationUrl() {
-    return service.getAuthorizationUrl();
+    if (enablePKCE) {
+      authorizationUrlBuilder.initPKCE();
+    }
+    return authorizationUrlBuilder.build();
   }
 
   @Override
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 1772eeb..addd12e 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -98,6 +98,7 @@
     client-id = "<client-id>"
     client-secret = "<client-secret>"
     link-to-existing-gerrit-accounts = false
+    enable-pkce = false
 ```
 
 When one from the sections above is omitted, OAuth SSO is used.
@@ -364,3 +365,6 @@
 
 You can optionally set `link-to-existing-gerrit-accounts = true` if you want the provider to link a account based
 on the username instead of trying to create a new account, see migration from LDAP.
+
+You can optionally set `enable-pkce = true` if you want to use PKCE as part of the authorization workflow
+during login.