Merge branch 'stable-2.14'

* stable-2.14:
  ChangeApiImpl: Don't catch RestApiException on rebase
  Remove bouncycastle jar files from lib folder during init

Change-Id: If4c741d7f085f58e2bef2fe6ce3bb0a9777cb84a
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 2a14aad..d5b4f49 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -448,6 +448,46 @@
   }
 
   @Test
+  public void rebaseNotAllowedWithoutPermission() throws Exception {
+    // Create two changes both with the same parent
+    PushOneCommit.Result r = createChange();
+    testRepo.reset("HEAD~1");
+    PushOneCommit.Result r2 = createChange();
+
+    // Approve and submit the first change
+    RevisionApi revision = gApi.changes().id(r.getChangeId()).current();
+    revision.review(ReviewInput.approve());
+    revision.submit();
+
+    // Rebase the second
+    String changeId = r2.getChangeId();
+    setApiUser(user);
+    exception.expect(AuthException.class);
+    exception.expectMessage("rebase not permitted");
+    gApi.changes().id(changeId).rebase();
+  }
+
+  @Test
+  public void rebaseAllowedWithPermission() throws Exception {
+    // Create two changes both with the same parent
+    PushOneCommit.Result r = createChange();
+    testRepo.reset("HEAD~1");
+    PushOneCommit.Result r2 = createChange();
+
+    // Approve and submit the first change
+    RevisionApi revision = gApi.changes().id(r.getChangeId()).current();
+    revision.review(ReviewInput.approve());
+    revision.submit();
+
+    grant(Permission.REBASE, project, "refs/heads/master", false, REGISTERED_USERS);
+
+    // Rebase the second
+    String changeId = r2.getChangeId();
+    setApiUser(user);
+    gApi.changes().id(changeId).rebase();
+  }
+
+  @Test
   public void publish() throws Exception {
     PushOneCommit.Result r = createChange("refs/drafts/master");
     assertThat(info(r.getChangeId()).status).isEqualTo(ChangeStatus.DRAFT);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
index d3d4853..a563a55 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
@@ -41,12 +41,14 @@
   private final ConsoleUI ui;
   private final SitePaths site;
   private final Section sshd;
+  private final StaleLibraryRemover remover;
 
   @Inject
-  InitSshd(final ConsoleUI ui, final SitePaths site, final Section.Factory sections) {
+  InitSshd(ConsoleUI ui, SitePaths site, Section.Factory sections, StaleLibraryRemover remover) {
     this.ui = ui;
     this.site = site;
     this.sshd = sections.get("sshd", null);
+    this.remover = remover;
   }
 
   @Override
@@ -74,6 +76,7 @@
     sshd.set("listenAddress", SocketUtil.format(hostname, port));
 
     generateSshHostKeys();
+    remover.remove("bc(pg|pkix|prov)-.*[.]jar");
   }
 
   private static boolean isOff(String listenHostname) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
index f434681..0ba4083 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
@@ -14,7 +14,6 @@
 
 package com.google.gerrit.pgm.init;
 
-import com.google.common.base.Strings;
 import com.google.common.hash.Funnels;
 import com.google.common.hash.Hasher;
 import com.google.common.hash.Hashing;
@@ -33,7 +32,6 @@
 import java.net.ProxySelector;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -45,6 +43,7 @@
 class LibraryDownloader {
   private final ConsoleUI ui;
   private final Path lib_dir;
+  private final StaleLibraryRemover remover;
 
   private boolean required;
   private String name;
@@ -59,9 +58,10 @@
   private boolean skipDownload;
 
   @Inject
-  LibraryDownloader(ConsoleUI ui, SitePaths site) {
+  LibraryDownloader(ConsoleUI ui, SitePaths site, StaleLibraryRemover remover) {
     this.ui = ui;
     this.lib_dir = site.lib_dir;
+    this.remover = remover;
     this.needs = new ArrayList<>(2);
   }
 
@@ -169,7 +169,7 @@
     }
 
     try {
-      removeStaleVersions();
+      remover.remove(remove);
       if (download) {
         doGetByHttp();
       } else {
@@ -216,32 +216,6 @@
     }
   }
 
-  private void removeStaleVersions() {
-    if (!Strings.isNullOrEmpty(remove)) {
-      DirectoryStream.Filter<Path> filter =
-          new DirectoryStream.Filter<Path>() {
-            @Override
-            public boolean accept(Path entry) {
-              return entry.getFileName().toString().matches("^" + remove + "$");
-            }
-          };
-      try (DirectoryStream<Path> paths = Files.newDirectoryStream(lib_dir, filter)) {
-        for (Path p : paths) {
-          String old = p.getFileName().toString();
-          String bak = "." + old + ".backup";
-          ui.message("Renaming %s to %s\n", old, bak);
-          try {
-            Files.move(p, p.resolveSibling(bak));
-          } catch (IOException e) {
-            throw new Die("cannot rename " + old, e);
-          }
-        }
-      } catch (IOException e) {
-        throw new Die("cannot remove stale library versions", e);
-      }
-    }
-  }
-
   private void doGetByLocalCopy() throws IOException {
     System.err.print("Copying " + jarUrl + " ...");
     Path p = url2file(jarUrl);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/StaleLibraryRemover.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/StaleLibraryRemover.java
new file mode 100644
index 0000000..325ae12
--- /dev/null
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/StaleLibraryRemover.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2017 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.google.gerrit.pgm.init;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.common.Die;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class StaleLibraryRemover {
+  private final ConsoleUI ui;
+  private final Path lib_dir;
+
+  @Inject
+  StaleLibraryRemover(ConsoleUI ui, SitePaths site) {
+    this.ui = ui;
+    this.lib_dir = site.lib_dir;
+  }
+
+  public void remove(String pattern) {
+    if (!Strings.isNullOrEmpty(pattern)) {
+      DirectoryStream.Filter<Path> filter =
+          new DirectoryStream.Filter<Path>() {
+            @Override
+            public boolean accept(Path entry) {
+              return entry.getFileName().toString().matches("^" + pattern + "$");
+            }
+          };
+      try (DirectoryStream<Path> paths = Files.newDirectoryStream(lib_dir, filter)) {
+        for (Path p : paths) {
+          String old = p.getFileName().toString();
+          String bak = "." + old + ".backup";
+          ui.message("Renaming %s to %s\n", old, bak);
+          try {
+            Files.move(p, p.resolveSibling(bak));
+          } catch (IOException e) {
+            throw new Die("cannot rename " + old, e);
+          }
+        }
+      } catch (IOException e) {
+        throw new Die("cannot remove stale library versions", e);
+      }
+    }
+  }
+}
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
index e05d3de..af21ad0 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
@@ -31,6 +31,7 @@
   public void create() throws Exception {
     final SitePaths site = new SitePaths(Paths.get("."));
     final ConsoleUI ui = createStrictMock(ConsoleUI.class);
+    final StaleLibraryRemover remover = createStrictMock(StaleLibraryRemover.class);
 
     replay(ui);
 
@@ -39,7 +40,7 @@
             new Provider<LibraryDownloader>() {
               @Override
               public LibraryDownloader get() {
-                return new LibraryDownloader(ui, site);
+                return new LibraryDownloader(ui, site, remover);
               }
             },
             Collections.<String>emptyList(),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index 6005719..4367efa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -361,7 +361,7 @@
   public void rebase(RebaseInput in) throws RestApiException {
     try {
       rebase.apply(change, in);
-    } catch (EmailException | OrmException | UpdateException | RestApiException | IOException e) {
+    } catch (EmailException | OrmException | UpdateException | IOException e) {
       throw new RestApiException("Cannot rebase change", e);
     }
   }