Add a global capability to allow generating HTTP passwords

The capability `generateHttpPassword` allows non-administrator
users to generate HTTP passwords for users other than self.

This capability would typically be assigned to a non-interactive
group to be able to register HTTP passwords for users from a
tool or web service that uses the Gerrit REST API.

Change-Id: I3d77cd406b0258d68cd0b8bb4dfbdcec97112450
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 500d824..a3bfe27 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -1203,6 +1203,14 @@
 you need the <<capability_viewCaches,view caches capability>>.
 
 
+[[capability_generateHttpPassword]]
+Generate HTTP Password
+~~~~~~~~~~~~~~~~~~~~~~
+
+Allow the user to generate HTTP passwords for other users.  Typically this would
+be assigned to a non-interactive users group.
+
+
 [[capability_kill]]
 Kill Task
 ~~~~~~~~~
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
index 8c08feb..b8de9ae 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
@@ -58,6 +58,9 @@
   /** Can flush any cache except the active web_sessions cache. */
   public static final String FLUSH_CACHES = "flushCaches";
 
+  /** Can generate HTTP passwords for user other than self. */
+  public static final String GENERATE_HTTP_PASSWORD = "generateHttpPassword";
+
   /** Can terminate any task using the kill command. */
   public static final String KILL_TASK = "killTask";
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
index d2014ec..fad9465 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
@@ -154,6 +154,12 @@
         || canAdministrateServer();
   }
 
+  /** @return true if the user can generate HTTP passwords for users other than self. */
+  public boolean canGenerateHttpPassword() {
+    return canPerform(GlobalCapability.GENERATE_HTTP_PASSWORD)
+        || canAdministrateServer();
+  }
+
   /** @return which priority queue the user's tasks should be submitted to. */
   public QueueProvider.QueueType getQueueType() {
     // If a non-generic group (that is not Anonymous Users or Registered Users)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java
index fa6e4d6..e796cbb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java
@@ -68,13 +68,17 @@
   @Override
   public Response<String> apply(AccountResource rsrc, Input input) throws AuthException,
       ResourceNotFoundException, ResourceConflictException, OrmException {
-    if (self.get() != rsrc.getUser()
-        && !self.get().getCapabilities().canAdministrateServer()) {
-      throw new AuthException("not allowed to set HTTP password");
-    }
     if (input == null) {
       input = new Input();
     }
+    if (self.get() != rsrc.getUser()
+        && !self.get().getCapabilities().canAdministrateServer()) {
+      if (input.generate && !self.get().getCapabilities().canGenerateHttpPassword()) {
+        throw new AuthException("not allowed to generate HTTP password");
+      } else {
+        throw new AuthException("not allowed to set HTTP password");
+      }
+    }
     if (rsrc.getUser().getUserName() == null) {
       throw new ResourceConflictException("username must be set");
     }