CVE-2022-31128 (published 2022-08-01T17:15Z)

Tuleap is a Free & Open Source Suite to improve management of software developments and collaboration. In affected versions Tuleap does not properly verify permissions when creating branches with the REST API in Git repositories using the fine grained permissions. Users can create branches via the REST endpoint `POST git/:id/branches` regardless of the permissions set on the repository. This issue has been fixed in version 13.10.99.82 Tuleap Community Edition as well as in version 13.10-3 of Tuleap Enterprise Edition. Users are advised to upgrade. There are no known workarounds for this issue.

CVSS v3 base score: 5.4, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N)

Weakness information:
cwe_id: CWE-862
cwe_name: Missing Authorization
description: The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are not applied, users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         

Fix information:
repo_url: https://github.com/Enalean/tuleap
commit_details: repo_url: https://github.com/Enalean/tuleap
author: Yannis ROSSETTO
author_date: 2022-07-05 10:52:52+02:00
msg: fix: Fine grained permissions must be well handled in POST git/:id/branches

This fixes request #27538 Fine grained permissions are not checked when creating a branch with REST API

The fine grained permissions were not taken into account in the previous
checks.

Change-Id: I1fa72ab34e4f41d5ea3ec9dd21e990ce330d780f
repository: repo_url: https://github.com/Enalean/tuleap
repo_name: Enalean/tuleap
description: Tuleap is an Open Source Suite to improve management of software developments and collaboration. With a single web-based solution, project managers, developers & quality managers can easily build, deploy software projects.
repo_language: PHP
owner: Enalean
file_changes: filename: BranchCreator.php
change_type: ModificationType.MODIFY
diff: @@ -21,21 +21,24 @@
 
 namespace Tuleap\Git\REST\v1\Branch;
 
-use Git;
 use Git_Command_Exception;
 use Luracast\Restler\RestException;
 use Tuleap\Git\Branch\BranchCreationExecutor;
 use Tuleap\Git\Branch\BranchName;
 use Tuleap\Git\Branch\CannotCreateNewBranchException;
 use Tuleap\Git\Branch\InvalidBranchNameException;
+use Tuleap\Git\Permissions\AccessControlVerifier;
 use Tuleap\Git\REST\v1\GitBranchPOSTRepresentation;
 
 class BranchCreator
 {
     private const BRANCH_PREFIX = "refs/heads/";
 
-    public function __construct(private \Git_Exec $git_exec, private BranchCreationExecutor $branch_creation_executor)
-    {
+    public function __construct(
+        private \Git_Exec $git_exec,
+        private BranchCreationExecutor $branch_creation_executor,
+        private AccessControlVerifier $access_control_verifier,
+    ) {
     }
 
     /**
@@ -43,16 +46,6 @@ class BranchCreator
      */
     public function createBranch(\PFUser $user, \GitRepository $repository, GitBranchPOSTRepresentation $representation): void
     {
-        if (
-            ! $user->hasPermission(Git::PERM_WRITE, $repository->getId(), $repository->getProjectId())
-            && ! $user->hasPermission(Git::PERM_WPLUS, $repository->getId(), $repository->getProjectId())
-        ) {
-            throw new RestException(
-                403,
-                "User cannot update the content of the repository"
-            );
-        }
-
         try {
             BranchName::fromBranchNameShortHand($representation->branch_name);
         } catch (InvalidBranchNameException $exception) {
@@ -65,6 +58,17 @@ class BranchCreator
             );
         }
 
+        if (! $this->access_control_verifier->canWrite($user, $repository, self::BRANCH_PREFIX . $representation->branch_name)) {
+            throw new RestException(
+                403,
+                sprintf(
+                    "You are not allowed to create the branch %s in repository %s",
+                    $representation->branch_name,
+                    $repository->getName()
+                )
+            );
+        }
+
         $all_branches_names = $this->git_exec->getAllBranchesSortedByCreationDate();
         if (in_array($representation->branch_name, $all_branches_names)) {
             throw new RestException(

programming_language: PHP
filename: RepositoryResource.class.php
change_type: ModificationType.MODIFY
diff: @@ -72,6 +72,7 @@ use Tuleap\Git\Gitolite\VersionDetector;
 use Tuleap\Git\GitPHP\ProjectProvider;
 use Tuleap\Git\GitPHP\RepositoryAccessException;
 use Tuleap\Git\GitPHP\RepositoryNotExistingException;
+use Tuleap\Git\Permissions\AccessControlVerifier;
 use Tuleap\Git\Permissions\DefaultFineGrainedPermissionFactory;
 use Tuleap\Git\Permissions\FineGrainedDao;
 use Tuleap\Git\Permissions\FineGrainedPatternValidator;
@@ -919,7 +920,18 @@ class RepositoryResource extends AuthenticatedResource
 
         $repository = $this->getRepositoryForCurrentUser($id);
 
-        (new BranchCreator(new Git_Exec($repository->getFullPath(), $repository->getFullPath()), new BranchCreationExecutor()))->createBranch(
+        $branch_creator = new BranchCreator(
+            new Git_Exec($repository->getFullPath(), $repository->getFullPath()),
+            new BranchCreationExecutor(),
+            new AccessControlVerifier(
+                new FineGrainedRetriever(
+                    new FineGrainedDao(),
+                ),
+                new \System_Command(),
+            )
+        );
+
+        $branch_creator->createBranch(
             $this->getCurrentUser(),
             $repository,
             $representation

programming_language: PHP
filename: BranchCreatorTest.php
change_type: ModificationType.MODIFY
diff: @@ -23,12 +23,13 @@ declare(strict_types=1);
 
 namespace Tuleap\Git\REST\v1\Branch;
 
-use Git;
 use Git_Command_Exception;
 use Luracast\Restler\RestException;
 use Tuleap\Git\Branch\BranchCreationExecutor;
 use Tuleap\Git\Branch\CannotCreateNewBranchException;
+use Tuleap\Git\Permissions\AccessControlVerifier;
 use Tuleap\Git\REST\v1\GitBranchPOSTRepresentation;
+use Tuleap\Test\Builders\UserTestBuilder;
 use Tuleap\Test\PHPUnit\TestCase;
 
 final class BranchCreatorTest extends TestCase
@@ -45,6 +46,10 @@ final class BranchCreatorTest extends TestCase
      * @var \PHPUnit\Framework\MockObject\MockObject&BranchCreationExecutor
      */
     private $branch_creation_executor;
+    /**
+     * @var AccessControlVerifier&\PHPUnit\Framework\MockObject\MockObject
+     */
+    private $access_control_verifier;
 
     protected function setUp(): void
     {
@@ -52,10 +57,12 @@ final class BranchCreatorTest extends TestCase
 
         $this->git_exec                 = $this->createMock(\Git_Exec::class);
         $this->branch_creation_executor = $this->createMock(BranchCreationExecutor::class);
+        $this->access_control_verifier  = $this->createMock(AccessControlVerifier::class);
 
         $this->creator = new BranchCreator(
             $this->git_exec,
-            $this->branch_creation_executor
+            $this->branch_creation_executor,
+            $this->access_control_verifier
         );
 
         $this->git_exec->method('getAllBranchesSortedByCreationDate')->willReturn([
@@ -90,7 +97,7 @@ final class BranchCreatorTest extends TestCase
             ->method("createNewBranch");
 
         $this->expectException(RestException::class);
-        $this->expectExceptionMessage("User cannot update the content of the repository");
+        $this->expectExceptionMessage("You are not allowed to create the branch new_branch in repository repo01");
 
         $this->creator->createBranch(
             $this->buildMockUserWithoutPermissions(),
@@ -201,22 +208,16 @@ final class BranchCreatorTest extends TestCase
 
     private function buildMockUserWithPermissions(): \PFUser
     {
-        $user = $this->createMock(\PFUser::class);
-        $user->method('hasPermission')->willReturnMap([
-            [Git::PERM_WRITE, self::REPO_ID, self::PROJECT_ID, true],
-            [Git::PERM_WPLUS, self::REPO_ID, self::PROJECT_ID, true],
-        ]);
+        $user = UserTestBuilder::anActiveUser()->build();
+        $this->access_control_verifier->method('canWrite')->willReturn(true);
 
         return $user;
     }
 
     private function buildMockUserWithoutPermissions(): \PFUser
     {
-        $user = $this->createMock(\PFUser::class);
-        $user->method('hasPermission')->willReturnMap([
-            [Git::PERM_WRITE, self::REPO_ID, self::PROJECT_ID, false],
-            [Git::PERM_WPLUS, self::REPO_ID, self::PROJECT_ID, false],
-        ]);
+        $user = UserTestBuilder::anActiveUser()->build();
+        $this->access_control_verifier->method('canWrite')->willReturn(false);
 
         return $user;
     }

programming_language: PHP