Allow admins to limit timeouts, retries and retry interval

These new configs provide improved guardrails for admins against
unreasonable values in the per-project plugin config.

Change-Id: Icba6bf1d94f47ca09b992f2f5b85e39b216ba48d
diff --git a/src/main/java/com/googlesource/gerrit/plugins/webhooks/Configuration.java b/src/main/java/com/googlesource/gerrit/plugins/webhooks/Configuration.java
index 44026fc..eb54ec2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/Configuration.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/Configuration.java
@@ -24,6 +24,10 @@
 public class Configuration {
   public static final String THREAD_POOL_SIZE = "threadPoolSize";
   public static final String ALLOWED_EVENT = "allowedEvent";
+  public static final String MAX_ALLOWED_CONNECTION_TIMEOUT = "maxAllowedConnectionTimeout";
+  public static final String MAX_ALLOWED_SOCKET_TIMEOUT = "maxAllowedSocketTimeout";
+  public static final String MAX_ALLOWED_TRIES = "maxAllowedTries";
+  public static final String MAX_ALLOWED_RETRY_INTERVAL = "maxAllowedRetryInterval";
 
   public static final int DEFAULT_TIMEOUT_MS = 5000;
   public static final int DEFAULT_MAX_TRIES = 5;
@@ -38,6 +42,10 @@
   private final int threadPoolSize;
   private final boolean sslVerify;
   private final String[] allowedEvents;
+  private final int maxAllowedConnectionTimeout;
+  private final int maxAllowedSocketTimeout;
+  private final int maxAllowedTries;
+  private final int maxAllowedRetryInterval;
 
   @Inject
   protected Configuration(PluginConfigFactory config, @PluginName String pluginName) {
@@ -49,6 +57,10 @@
     threadPoolSize = cfg.getInt(THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE);
     sslVerify = cfg.getBoolean(RemoteConfig.SSL_VERIFY, DEFAULT_SSL_VERIFY);
     allowedEvents = cfg.getStringList(ALLOWED_EVENT);
+    maxAllowedConnectionTimeout = cfg.getInt(MAX_ALLOWED_CONNECTION_TIMEOUT, 0);
+    maxAllowedSocketTimeout = cfg.getInt(MAX_ALLOWED_SOCKET_TIMEOUT, 0);
+    maxAllowedTries = cfg.getInt(MAX_ALLOWED_TRIES, 0);
+    maxAllowedRetryInterval = cfg.getInt(MAX_ALLOWED_RETRY_INTERVAL, 0);
   }
 
   public int getConnectionTimeout() {
@@ -78,4 +90,20 @@
   public String[] getAllowedEvents() {
     return allowedEvents;
   }
+
+  public int getMaxAllowedConnectionTimeout() {
+    return maxAllowedConnectionTimeout;
+  }
+
+  public int getMaxAllowedSocketTimeout() {
+    return maxAllowedSocketTimeout;
+  }
+
+  public int getMaxAllowedTries() {
+    return maxAllowedTries;
+  }
+
+  public int getMaxAllowedRetryInterval() {
+    return maxAllowedRetryInterval;
+  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/webhooks/RemoteConfig.java b/src/main/java/com/googlesource/gerrit/plugins/webhooks/RemoteConfig.java
index 542a3a9..5b9686a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/RemoteConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/RemoteConfig.java
@@ -68,19 +68,32 @@
   }
 
   public int getConnectionTimeout() {
-    return config.getInt(REMOTE, name, CONNECTION_TIMEOUT, global.getConnectionTimeout());
+    int connectionTimeout =
+        config.getInt(REMOTE, name, CONNECTION_TIMEOUT, global.getConnectionTimeout());
+    return (global.getMaxAllowedConnectionTimeout() > 0)
+        ? Math.min(connectionTimeout, global.getMaxAllowedConnectionTimeout())
+        : connectionTimeout;
   }
 
   public int getSocketTimeout() {
-    return config.getInt(REMOTE, name, SOCKET_TIMEOUT, global.getSocketTimeout());
+    int socketTimeout = config.getInt(REMOTE, name, SOCKET_TIMEOUT, global.getSocketTimeout());
+    return (global.getMaxAllowedSocketTimeout() > 0)
+        ? Math.min(socketTimeout, global.getMaxAllowedSocketTimeout())
+        : socketTimeout;
   }
 
   public int getMaxTries() {
-    return config.getInt(REMOTE, name, MAX_TRIES, global.getMaxTries());
+    int maxTries = config.getInt(REMOTE, name, MAX_TRIES, global.getMaxTries());
+    return (global.getMaxAllowedTries() > 0)
+        ? Math.min(maxTries, global.getMaxAllowedTries())
+        : maxTries;
   }
 
   public int getRetryInterval() {
-    return config.getInt(REMOTE, name, RETRY_INTERVAL, global.getRetryInterval());
+    int retryInterval = config.getInt(REMOTE, name, RETRY_INTERVAL, global.getRetryInterval());
+    return (global.getMaxAllowedRetryInterval() > 0)
+        ? Math.min(retryInterval, global.getMaxAllowedRetryInterval())
+        : retryInterval;
   }
 
   public boolean getSslVerify() {
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 88f99f1..280b8e7 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -71,6 +71,25 @@
     Multiple event types can be provided. If not specified, then all event
     types are allowed.
 
+@PLUGIN@.maxAllowedConnectionTimeout
+:   Maximum allowed value for the connection timeout. If a value greater than
+    this is configured in the @PLUGIN@.config, this value will be chosen
+    instead.
+
+@PLUGIN@.maxAllowedSocketTimeout
+:   Maximum allowed value for the socket timeout. If a value greater than
+    this is configured in the @PLUGIN@.config, this value will be chosen
+    instead.
+
+@PLUGIN@.maxAllowedTries
+:   Maximum allowed value for the retries. If a value greater than this is
+    configured in the @PLUGIN@.config, this value will be chosen instead.
+
+@PLUGIN@.maxAllowedRetryInterval
+:   Maximum allowed value for the retry interval. If a value greater than
+    this is configured in the @PLUGIN@.config, this value will be chosen
+    instead.
+
 
 File '@PLUGIN@.config'
 ----------------------