Merge branch 'stable-2.16'

* stable-2.16:
  Auth: check the ability to authenticate users

Change-Id: I81c7c6c8ae23cc428f484b969f80de2231b27dac
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java
index 98df366..5e1c7ea 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java
@@ -38,6 +38,8 @@
   private static final long HEALTHCHECK_TIMEOUT_DEFAULT = 500L;
   private static final String QUERY_DEFAULT = "status:open";
   private static final int LIMIT_DEFAULT = 10;
+  private static final String USERNAME_DEFAULT = "healthcheck";
+  private static final String PASSWORD_DEFAULT = "";
   private final AllProjectsName allProjectsName;
   private final AllUsersName allUsersName;
 
@@ -79,9 +81,7 @@
   }
 
   public String getQuery(String healthCheckName) {
-    String defaultQuery = healthCheckName == null ? QUERY_DEFAULT : getQuery(null);
-    return MoreObjects.firstNonNull(
-        config.getString(HEALTHCHECK, healthCheckName, "query"), defaultQuery);
+    return getStringWithFallback("query", healthCheckName, QUERY_DEFAULT);
   }
 
   public int getLimit(String healthCheckName) {
@@ -98,4 +98,22 @@
     repos.add(allUsersName);
     return repos;
   }
+
+  public String getUsername(String healthCheckName) {
+    return getStringWithFallback("userame", healthCheckName, USERNAME_DEFAULT);
+  }
+
+  public String getPassword(String healthCheckName) {
+    return getStringWithFallback("password", healthCheckName, PASSWORD_DEFAULT);
+  }
+
+  private String getStringWithFallback(
+      String parameter, String healthCheckName, String defaultValue) {
+    String fallbackDefault =
+        healthCheckName == null
+            ? defaultValue
+            : getStringWithFallback(parameter, null, defaultValue);
+    return MoreObjects.firstNonNull(
+        config.getString(HEALTHCHECK, healthCheckName, parameter), fallbackDefault);
+  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
index 277c11f..a7eb01a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
@@ -17,6 +17,7 @@
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.inject.AbstractModule;
+import com.googlesource.gerrit.plugins.healthcheck.check.AuthHealthCheck;
 import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
 import com.googlesource.gerrit.plugins.healthcheck.check.JGitHealthCheck;
 import com.googlesource.gerrit.plugins.healthcheck.check.ProjectsListHealthCheck;
@@ -29,6 +30,7 @@
     bindChecker(JGitHealthCheck.class);
     bindChecker(ProjectsListHealthCheck.class);
     bindChecker(QueryChangesHealthCheck.class);
+    bindChecker(AuthHealthCheck.class);
     bind(LifecycleListener.class).to(HealthCheckMetrics.class);
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AuthHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AuthHealthCheck.java
new file mode 100644
index 0000000..0dcb7a5
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AuthHealthCheck.java
@@ -0,0 +1,70 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.healthcheck.check;
+
+import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.AUTH;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.account.AuthRequest;
+import com.google.gerrit.server.account.Realm;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import java.util.Optional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class AuthHealthCheck extends AbstractHealthCheck {
+  private static final Logger log = LoggerFactory.getLogger(AuthHealthCheck.class);
+  private final Realm realm;
+  private final AccountCache byIdCache;
+  private final String username;
+  private final String password;
+
+  @Inject
+  public AuthHealthCheck(
+      ListeningExecutorService executor,
+      HealthCheckConfig config,
+      Realm realm,
+      AccountCache byIdCache) {
+    super(executor, config, AUTH);
+
+    this.realm = realm;
+    this.byIdCache = byIdCache;
+    this.username = config.getUsername(AUTH);
+    this.password = config.getPassword(AUTH);
+  }
+
+  @Override
+  protected Result doCheck() throws Exception {
+    AuthRequest authRequest = AuthRequest.forUser(username);
+    authRequest.setPassword(password);
+    realm.authenticate(authRequest);
+
+    Optional<AccountState> accountState = byIdCache.getByUsername(username);
+    if (!accountState.isPresent()) {
+      log.error("Cannot load account state for username " + username);
+      return Result.FAILED;
+    }
+    if (!accountState.get().getAccount().isActive()) {
+      log.error("Authentication error, account " + username + " is inactive");
+      return Result.FAILED;
+    }
+    return Result.PASSED;
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
index 670e1b4..143d2b1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
@@ -18,4 +18,5 @@
   String JGIT = "jgit";
   String PROJECTSLIST = "projectslist";
   String QUERYCHANGES = "querychanges";
+  String AUTH = "auth";
 }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 0a9fa22..838db79 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -47,6 +47,7 @@
 - `querychanges`: check the ability to query changes
 - `jgit` : check connectivity to the filesystem and ability to open a JGit ref and object
 - `projectslist` : check the ability to list projects with their descriptions
+- `auth`: check the ability to authenticate with username and password
 
 The follwing parameters are available:
 
@@ -70,3 +71,11 @@
    to the default ones that are always included.
 
   Default: All-Projects, All-Users
+  
+ - `healthcheck.auth.username` : Username to use for authentication
+ 
+   Default: healthcheck
+   
+ - `healthcheck.auth.password` : Password to use for authentication
+ 
+   Default: no password
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
index 331c784..24bfc81 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
@@ -58,6 +58,7 @@
     for (int i = 0; i < numChanges; i++) {
       createChange("refs/for/master");
     }
+    accountCreator.create(config.getUsername(HealthCheckNames.AUTH));
   }
 
   @Test