Merge branch 'stable-2.5'

* stable-2.5:
  Improve wording in Gerrit 2.5.1 release notes
  Add release notes for Gerrit 2.5.1
  Allow assigning Push for refs/meta/config on All-Projects
  Fix auto closing of changes on direct push
  Match all git fetch/clone/push commands to the command executor
  Fix RequestCleanup bug with Git over HTTP
  Make sure only Gerrit admins can change the parent of a project
  Correctly identify Git-over-HTTP operations

Conflicts:
	gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
	gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java
	gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
	gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java

The modification done by
  Correctly identify Git-over-HTTP operations
were discarded since the issue fixed by this commit is already fixed in
master.

Change-Id: If16c8f8e99a481917661049da6a0e853b9febc84
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/ReleaseNotes/ReleaseNotes-2.5.1.txt b/ReleaseNotes/ReleaseNotes-2.5.1.txt
new file mode 100644
index 0000000..967d78d
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.5.1.txt
@@ -0,0 +1,94 @@
+Release notes for Gerrit 2.5.1
+==============================
+
+Gerrit 2.5.1 is now available:
+
+link:http://code.google.com/p/gerrit/downloads/detail?name=gerrit-full-2.5.1.war[http://code.google.com/p/gerrit/downloads/detail?name=gerrit-full-2.5.1.war]
+
+There are no schema changes from 2.5, or 2.5.1.
+
+However, if upgrading from anything earlier version, follow the upgrade
+procedure in the 2.5 link:ReleaseNotes-2.5.html[Release Notes].
+
+Security Fixes
+--------------
+* Correctly identify Git-over-HTTP operations
++
+Git operations over HTTP should be classified as using AccessPath.GIT
+and not WEB_UI. This ensures RefControl will correctly test for Create,
+Push or Delete access on a reference instead of Owner.
++
+E.g. without this fix project owners are able to force push commits
+via HTTP that are already in the history of the target branch, even
+without having any Push access right assigned.
+
+* Make sure only Gerrit admins can change the parent of a project
++
+Only Gerrit administrators should be able to change the parent of a
+project because by changing the parent project access rights and BLOCK
+rules which are configured on a parent project can be avoided.
++
+The `set-project-parent` SSH command already verifies that the caller
+is a Gerrit administrator, however project owners can change the parent
+project by modifying the `project.config` file and pushing to the
+`refs/meta/config` branch.
++
+This fix ensures that changes to the `project.config` file that change
+the parent project can only be pushed/submitted by Gerrit
+administrators.
++
+In addition it is now no longer possible to
+- set a non-existing project as parent (as this would make the project
+  be orphaned)
+- set a parent project for the `All-Projects` root project (the root
+  project by definition has no parent)
+by pushing changes of the `project.config` file to `refs/meta/config`.
+
+Bug Fixes
+---------
+* Fix RequestCleanup bug with Git over HTTP
++
+Decide if a continuation is going to be used early, before the filter
+that will attempt to cleanup a RequestCleanup. If so don't allow
+entering the RequestCleanup part of the system until the request is
+actually going to be processed.
++
+This fixes the IllegalStateException `Request has already been cleaned
+up` that occurred when running on Jetty and pushing over HTTP for URLs
+where the path starts with `/p/`.
+
+* Match all git fetch/clone/push commands to the command executor
++
+Route not just `/p/` but any Git access to the same thread pool as the
+SSH server is using, allowing all requests to compete fairly for
+resources.
+
+* Fix auto closing of changes on direct push
++
+When a commit is directly pushed into a repository (bypassing code
+review) and this commit has a Change-Id in its commit message then the
+corresponding change is automatically closed if it is open.
+
+* Allow assigning `Push` for `refs/meta/config` on `All-Projects`
++
+The `refs/meta/config` branch of the `All-Projects project` should only
+be modified by Gerrit administrators because being able to do
+modifications on this branch means that the user could assign himself
+administrator permissions.
++
+In addition to being administrator we already require that the
+administrator has the `Push` access right for `refs/meta/config` in
+order to be able to modify it (just as with all other branches
+administrators do not have edit permissions by default).
++
+The problem was that assigning the `Push` access right for
+`refs/meta/config` on the `All-Projects` project was not allowed.
++
+Having the `Push` access right for `refs/meta/config` on the
+`All-Projects` project without being administrator already has no
+effect.
++
+Prohibiting to assign the Push access right for `refs/meta/config` on
+the `All-Project` project was anyway pointless since it was e.g.
+possible to assign the `Push` access right on `refs/meta/*`.
+
diff --git a/ReleaseNotes/index.txt b/ReleaseNotes/index.txt
index 452057c..02c1a2c 100644
--- a/ReleaseNotes/index.txt
+++ b/ReleaseNotes/index.txt
@@ -4,6 +4,7 @@
 [[2_5]]
 Version 2.5.x
 -------------
+* link:ReleaseNotes-2.5.1.html[2.5.1]
 * link:ReleaseNotes-2.5.html[2.5]
 
 [[2_4]]
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/CommitMergeStatus.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/CommitMergeStatus.java
index 65b5139..7dbba04 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/CommitMergeStatus.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/CommitMergeStatus.java
@@ -62,7 +62,26 @@
   /** */
   NOT_FAST_FORWARD("Project policy requires all submissions to be a fast-forward.\n"
                   + "\n"
-                  + "Please rebase the change locally and upload again for review.");
+                  + "Please rebase the change locally and upload again for review."),
+
+  /** */
+  INVALID_PROJECT_CONFIGURATION("Change contains an invalid project configuration."),
+
+  /** */
+  INVALID_PROJECT_CONFIGURATION_PARENT_PROJECT_NOT_FOUND(
+      "Change contains an invalid project configuration:\n"
+          + "Parent project does not exist."),
+
+  /** */
+  INVALID_PROJECT_CONFIGURATION_ROOT_PROJECT_CANNOT_HAVE_PARENT(
+      "Change contains an invalid project configuration:\n"
+          + "The root project cannot have a parent."),
+
+  /** */
+  SETTING_PARENT_PROJECT_ONLY_ALLOWED_BY_ADMIN(
+      "Change contains a project configuration that changes the parent project.\n"
+          + "The change must be submitted by a Gerrit administrator.");
+
 
   private String message;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index 3ab24a6..a889e18 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -42,6 +42,7 @@
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 import com.google.gerrit.server.mail.MergeFailSender;
 import com.google.gerrit.server.mail.MergedSender;
@@ -153,6 +154,7 @@
   private final SubmoduleOp.Factory subOpFactory;
   private final WorkQueue workQueue;
   private final RequestScopePropagator requestScopePropagator;
+  private final AllProjectsName allProjectsName;
 
   @Inject
   MergeOp(final GitRepositoryManager grm, final SchemaFactory<ReviewDb> sf,
@@ -169,7 +171,8 @@
       final SubmitStrategyFactory submitStrategyFactory,
       final SubmoduleOp.Factory subOpFactory,
       final WorkQueue workQueue,
-      final RequestScopePropagator requestScopePropagator) {
+      final RequestScopePropagator requestScopePropagator,
+      final AllProjectsName allProjectsName) {
     repoManager = grm;
     schemaFactory = sf;
     functionState = fs;
@@ -190,6 +193,7 @@
     this.subOpFactory = subOpFactory;
     this.workQueue = workQueue;
     this.requestScopePropagator = requestScopePropagator;
+    this.allProjectsName = allProjectsName;
     this.myIdent = myIdent;
     destBranch = branch;
     toMerge = ArrayListMultimap.create();
@@ -542,6 +546,52 @@
         continue;
       }
 
+      if (GitRepositoryManager.REF_CONFIG.equals(destBranch.get())) {
+        final Project.NameKey newParent;
+        try {
+          ProjectConfig cfg =
+              new ProjectConfig(destProject.getProject().getNameKey());
+          cfg.load(repo, commit);
+          newParent = cfg.getProject().getParent(allProjectsName);
+        } catch (Exception e) {
+          commits.put(changeId, CodeReviewCommit
+              .error(CommitMergeStatus.INVALID_PROJECT_CONFIGURATION));
+          continue;
+        }
+        final Project.NameKey oldParent =
+            destProject.getProject().getParent(allProjectsName);
+        if (oldParent == null) {
+          // update of the 'All-Projects' project
+          if (newParent != null) {
+            commits.put(changeId, CodeReviewCommit
+                .error(CommitMergeStatus.INVALID_PROJECT_CONFIGURATION_ROOT_PROJECT_CANNOT_HAVE_PARENT));
+            continue;
+          }
+        } else {
+          if (!oldParent.equals(newParent)) {
+            final PatchSetApproval psa = getSubmitter(db, ps.getId());
+            if (psa == null) {
+              commits.put(changeId, CodeReviewCommit
+                  .error(CommitMergeStatus.SETTING_PARENT_PROJECT_ONLY_ALLOWED_BY_ADMIN));
+              continue;
+            }
+            final IdentifiedUser submitter =
+                identifiedUserFactory.create(psa.getAccountId());
+            if (!submitter.getCapabilities().canAdministrateServer()) {
+              commits.put(changeId, CodeReviewCommit
+                  .error(CommitMergeStatus.SETTING_PARENT_PROJECT_ONLY_ALLOWED_BY_ADMIN));
+              continue;
+            }
+
+            if (projectCache.get(newParent) == null) {
+              commits.put(changeId, CodeReviewCommit
+                  .error(CommitMergeStatus.INVALID_PROJECT_CONFIGURATION_PARENT_PROJECT_NOT_FOUND));
+              continue;
+            }
+          }
+        }
+      }
+
       commit.change = chg;
       commit.patchsetId = ps.getId();
       commit.originalOrder = commitOrder++;
@@ -702,7 +752,11 @@
         case PATH_CONFLICT:
         case CRISS_CROSS_MERGE:
         case CANNOT_CHERRY_PICK_ROOT:
-        case NOT_FAST_FORWARD: {
+        case NOT_FAST_FORWARD:
+        case INVALID_PROJECT_CONFIGURATION:
+        case INVALID_PROJECT_CONFIGURATION_PARENT_PROJECT_NOT_FOUND:
+        case INVALID_PROJECT_CONFIGURATION_ROOT_PROJECT_CANNOT_HAVE_PARENT:
+        case SETTING_PARENT_PROJECT_ONLY_ALLOWED_BY_ADMIN: {
           setNew(c, message(c, txt));
           break;
         }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index 74ea2e5..578fcc0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -58,6 +58,7 @@
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountResolver;
+import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.TrackingFooters;
 import com.google.gerrit.server.events.CommitReceivedEvent;
@@ -256,6 +257,7 @@
   private final ListeningExecutorService changeUpdateExector;
   private final RequestScopePropagator requestScopePropagator;
   private final SshInfo sshInfo;
+  private final AllProjectsName allProjectsName;
 
   private final ProjectControl projectControl;
   private final Project project;
@@ -313,6 +315,7 @@
       final RequestScopePropagator requestScopePropagator,
       final SshInfo sshInfo,
       final DynamicSet<CommitValidationListener> commitValidationListeners,
+      final AllProjectsName allProjectsName,
       @Assisted final ProjectControl projectControl,
       @Assisted final Repository repo,
       final SubmoduleOp.Factory subOpFactory) throws IOException {
@@ -337,6 +340,7 @@
     this.changeUpdateExector = changeUpdateExector;
     this.requestScopePropagator = requestScopePropagator;
     this.sshInfo = sshInfo;
+    this.allProjectsName = allProjectsName;
 
     this.projectControl = projectControl;
     this.project = projectControl.getProject();
@@ -838,6 +842,26 @@
                     + cmd.getNewId().name() + " for " + project.getName());
                 continue;
               }
+              Project.NameKey newParent = cfg.getProject().getParent(allProjectsName);
+              Project.NameKey oldParent = project.getParent(allProjectsName);
+              if (oldParent == null) {
+                // update of the 'All-Projects' project
+                if (newParent != null) {
+                  reject(cmd, "invalid project configuration: root project cannot have parent");
+                  continue;
+                }
+              } else {
+                if (!oldParent.equals(newParent)
+                    && !currentUser.getCapabilities().canAdministrateServer()) {
+                  reject(cmd, "invalid project configuration: only Gerrit admin can set parent");
+                  continue;
+                }
+
+                if (projectCache.get(newParent) == null) {
+                  reject(cmd, "invalid project configuration: parent does not exist");
+                  continue;
+                }
+              }
             } catch (Exception e) {
               reject(cmd, "invalid project configuration");
               log.error("User " + currentUser.getUserName()